fast-npm-meta 1.1.0 → 1.2.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.
Files changed (3) hide show
  1. package/dist/index.d.mts +149 -146
  2. package/dist/index.mjs +138 -250
  3. package/package.json +7 -7
package/dist/index.d.mts CHANGED
@@ -1,178 +1,182 @@
1
+ //#region ../shared/types.d.ts
1
2
  interface PackageManifest {
2
- name: string;
3
- distTags: Record<string, string> & {
4
- latest: string;
5
- };
6
- versionsMeta: Record<string, PackageVersionMeta>;
7
- timeCreated: string;
8
- timeModified: string;
9
- lastSynced: number;
3
+ name: string;
4
+ distTags: Record<string, string> & {
5
+ latest: string;
6
+ };
7
+ versionsMeta: Record<string, PackageVersionMeta>;
8
+ timeCreated: string;
9
+ timeModified: string;
10
+ lastSynced: number;
10
11
  }
11
12
  type Engines = Partial<Record<string, string>>;
12
13
  interface PackageVersionMeta {
13
- time?: string;
14
- engines?: Engines;
15
- deprecated?: string;
16
- provenance?: 'trustedPublisher' | boolean;
17
- integrity?: string;
14
+ time?: string;
15
+ engines?: Engines;
16
+ deprecated?: string;
17
+ provenance?: 'trustedPublisher' | boolean;
18
+ integrity?: string;
18
19
  }
19
20
  interface PackageVersionsInfo extends Pick<PackageManifest, 'name' | 'distTags' | 'lastSynced'> {
20
- versions: string[];
21
- specifier: string;
22
- time: {
23
- created: string;
24
- modified: string;
25
- } & Record<string, string>;
21
+ versions: string[];
22
+ specifier: string;
23
+ time: {
24
+ created: string;
25
+ modified: string;
26
+ } & Record<string, string>;
26
27
  }
27
28
  interface PackageVersionsInfoWithMetadata extends PackageManifest {
28
- specifier: string;
29
+ specifier: string;
29
30
  }
30
31
  interface PackageError {
31
- status: number;
32
- name: string;
33
- error: string;
32
+ status: number;
33
+ name: string;
34
+ error: string;
34
35
  }
35
36
  type MaybeError<T> = T | PackageError;
36
37
  interface PackageManifestError extends PackageError {
37
- lastSynced: number;
38
+ lastSynced: number;
38
39
  }
39
40
  interface ResolvedPackageVersion {
40
- name: string;
41
- version: string | null;
42
- specifier: string;
43
- publishedAt: string | null;
44
- lastSynced: number;
41
+ name: string;
42
+ version: string | null;
43
+ specifier: string;
44
+ publishedAt: string | null;
45
+ lastSynced: number;
45
46
  }
46
- interface ResolvedPackageVersionWithMetadata extends ResolvedPackageVersion, PackageVersionMeta {
47
- }
48
-
47
+ interface ResolvedPackageVersionWithMetadata extends ResolvedPackageVersion, PackageVersionMeta {}
48
+ //#endregion
49
+ //#region src/types.d.ts
49
50
  interface RetryOptions {
50
- /**
51
- * The number of times to retry the operation.
52
- *
53
- * @default 5
54
- */
55
- retries?: number;
56
- /**
57
- * The exponential factor to use.
58
- *
59
- * @default 2
60
- */
61
- factor?: number;
62
- /**
63
- * The number of milliseconds before starting the first retry.
64
- *
65
- * Set this to `0` to retry immediately with no delay.
66
- *
67
- * @default 1000
68
- */
69
- minTimeout?: number;
70
- /**
71
- * The maximum number of milliseconds between two retries.
72
- *
73
- * @default Infinity
74
- */
75
- maxTimeout?: number;
76
- /**
77
- * Randomizes the timeouts by multiplying with a factor between 1 and 2.
78
- *
79
- * @default false
80
- */
81
- randomize?: boolean;
51
+ /**
52
+ * The number of times to retry the operation.
53
+ *
54
+ * @default 5
55
+ */
56
+ retries?: number;
57
+ /**
58
+ * The exponential factor to use.
59
+ *
60
+ * @default 2
61
+ */
62
+ factor?: number;
63
+ /**
64
+ * The number of milliseconds before starting the first retry.
65
+ *
66
+ * Set this to `0` to retry immediately with no delay.
67
+ *
68
+ * @default 1000
69
+ */
70
+ minTimeout?: number;
71
+ /**
72
+ * The maximum number of milliseconds between two retries.
73
+ *
74
+ * @default Infinity
75
+ */
76
+ maxTimeout?: number;
77
+ /**
78
+ * Randomizes the timeouts by multiplying with a factor between 1 and 2.
79
+ *
80
+ * @default false
81
+ */
82
+ randomize?: boolean;
82
83
  }
83
84
  interface FetchOptions<Throw extends boolean = true> {
84
- /**
85
- * API endpoint for fetching package versions
86
- *
87
- * @default 'https://npm.antfu.dev/'
88
- */
89
- apiEndpoint?: string;
90
- /**
91
- * Fetch function
92
- *
93
- * @default [globalThis.fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
94
- */
95
- fetch?: typeof fetch;
96
- /**
97
- * Should throw error or return error object
98
- *
99
- * @default true
100
- */
101
- throw?: Throw;
85
+ /**
86
+ * API endpoint for fetching package versions
87
+ *
88
+ * @default 'https://npm.antfu.dev/'
89
+ */
90
+ apiEndpoint?: string;
91
+ /**
92
+ * Fetch function
93
+ *
94
+ * @default [globalThis.fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
95
+ */
96
+ fetch?: typeof fetch;
97
+ /**
98
+ * Should throw error or return error object
99
+ *
100
+ * @default true
101
+ */
102
+ throw?: Throw;
102
103
  }
103
104
  interface GetVersionsOptions<Metadata extends boolean = false, Throw extends boolean = true> extends FetchOptions<Throw> {
104
- /**
105
- * By pass cache and get the latest data
106
- *
107
- * @default false
108
- */
109
- force?: boolean;
110
- /**
111
- * Include all versions that are newer than the specified version
112
- *
113
- * @default false
114
- */
115
- loose?: boolean;
116
- /**
117
- * Includes metadata, this will change the return type
118
- *
119
- * @default false
120
- */
121
- metadata?: Metadata;
122
- /**
123
- * Only return versions published after this ISO date-time
124
- *
125
- * @default undefined
126
- */
127
- after?: string;
128
- /**
129
- * Retry options for the built-in retry mechanism
130
- *
131
- * Can be:
132
- * - `RetryOptions` object for fine-grained control
133
- * - `number` for simple retry count (uses defaults for other options)
134
- * - `false` to disable retries
135
- */
136
- retry?: RetryOptions | number | false;
105
+ /**
106
+ * By pass cache and get the latest data
107
+ *
108
+ * @default false
109
+ */
110
+ force?: boolean;
111
+ /**
112
+ * Include all versions that are newer than the specified version
113
+ *
114
+ * @default false
115
+ */
116
+ loose?: boolean;
117
+ /**
118
+ * Includes metadata, this will change the return type
119
+ *
120
+ * @default false
121
+ */
122
+ metadata?: Metadata;
123
+ /**
124
+ * Only return versions published after this ISO date-time
125
+ *
126
+ * @default undefined
127
+ */
128
+ after?: string;
129
+ /**
130
+ * Retry options for the built-in retry mechanism
131
+ *
132
+ * Can be:
133
+ * - `RetryOptions` object for fine-grained control
134
+ * - `number` for simple retry count (uses defaults for other options)
135
+ * - `false` to disable retries
136
+ */
137
+ retry?: RetryOptions | number | false;
137
138
  }
138
139
  interface GetLatestVersionOptions<Metadata extends boolean = false, Throw extends boolean = true> extends FetchOptions<Throw> {
139
- /**
140
- * By pass cache and get the latest data
141
- *
142
- * @default false
143
- */
144
- force?: boolean;
145
- /**
146
- * Includes metadata
147
- *
148
- * @default false
149
- */
150
- metadata?: Metadata;
151
- /**
152
- * Retry options for the built-in retry mechanism
153
- *
154
- * Can be:
155
- * - `RetryOptions` object for fine-grained control
156
- * - `number` for simple retry count (uses defaults for other options)
157
- * - `false` to disable retries
158
- */
159
- retry?: RetryOptions | number | false;
140
+ /**
141
+ * By pass cache and get the latest data
142
+ *
143
+ * @default false
144
+ */
145
+ force?: boolean;
146
+ /**
147
+ * Includes metadata
148
+ *
149
+ * @default false
150
+ */
151
+ metadata?: Metadata;
152
+ /**
153
+ * Retry options for the built-in retry mechanism
154
+ *
155
+ * Can be:
156
+ * - `RetryOptions` object for fine-grained control
157
+ * - `number` for simple retry count (uses defaults for other options)
158
+ * - `false` to disable retries
159
+ */
160
+ retry?: RetryOptions | number | false;
160
161
  }
161
162
  type InferGetVersionsResult<Metadata, Throw> = Metadata extends true ? Throw extends true ? PackageVersionsInfoWithMetadata : MaybeError<PackageVersionsInfoWithMetadata> : Throw extends true ? PackageVersionsInfo : MaybeError<PackageVersionsInfo>;
162
163
  type InferGetLatestVersionResult<Metadata, Throw> = Metadata extends true ? Throw extends true ? ResolvedPackageVersionWithMetadata : MaybeError<ResolvedPackageVersionWithMetadata> : Throw extends true ? ResolvedPackageVersion : MaybeError<ResolvedPackageVersion>;
164
+ //#endregion
165
+ //#region src/api.d.ts
163
166
  declare const defaultOptions: {
164
- /**
165
- * API endpoint for fetching package versions
166
- *
167
- * @default 'https://npm.antfu.dev/'
168
- */
169
- apiEndpoint: string;
167
+ /**
168
+ * API endpoint for fetching package versions
169
+ *
170
+ * @default 'https://npm.antfu.dev/'
171
+ */
172
+ apiEndpoint: string;
170
173
  };
171
174
  declare function getLatestVersionBatch<Metadata extends boolean = false, Throw extends boolean = true>(packages: string[], options?: GetLatestVersionOptions<Metadata, Throw>): Promise<InferGetLatestVersionResult<Metadata, Throw>[]>;
172
175
  declare function getLatestVersion<Metadata extends boolean = false, Throw extends boolean = true>(name: string, options?: GetLatestVersionOptions<Metadata, Throw>): Promise<InferGetLatestVersionResult<Metadata, Throw>>;
173
176
  declare function getVersionsBatch<Metadata extends boolean = false, Throw extends boolean = true>(packages: string[], options?: GetVersionsOptions<Metadata, Throw>): Promise<InferGetVersionsResult<Metadata, Throw>[]>;
174
177
  declare function getVersions<Metadata extends boolean = false, Throw extends boolean = true>(name: string, options?: GetVersionsOptions<Metadata, Throw>): Promise<InferGetVersionsResult<Metadata, Throw>>;
175
-
178
+ //#endregion
179
+ //#region src/helpers.d.ts
176
180
  declare const NPM_REGISTRY = "https://registry.npmjs.org/";
177
181
  /**
178
182
  * Lightweight replacement of `npm-registry-fetch` function `pickRegistry`'
@@ -182,6 +186,5 @@ declare const NPM_REGISTRY = "https://registry.npmjs.org/";
182
186
  * @param defaultRegistry - default registry, default to 'https://registry.npmjs.org/'
183
187
  */
184
188
  declare function pickRegistry(scope: string | null | undefined, npmConfigs: Record<string, unknown>, defaultRegistry?: string): string;
185
-
186
- export { NPM_REGISTRY, defaultOptions, getLatestVersion, getLatestVersionBatch, getVersions, getVersionsBatch, pickRegistry };
187
- export type { Engines, FetchOptions, GetLatestVersionOptions, GetVersionsOptions, InferGetLatestVersionResult, InferGetVersionsResult, MaybeError, PackageError, PackageManifest, PackageManifestError, PackageVersionMeta, PackageVersionsInfo, PackageVersionsInfoWithMetadata, ResolvedPackageVersion, ResolvedPackageVersionWithMetadata, RetryOptions };
189
+ //#endregion
190
+ export { Engines, FetchOptions, GetLatestVersionOptions, GetVersionsOptions, InferGetLatestVersionResult, InferGetVersionsResult, MaybeError, NPM_REGISTRY, PackageError, PackageManifest, PackageManifestError, PackageVersionMeta, PackageVersionsInfo, PackageVersionsInfoWithMetadata, ResolvedPackageVersion, ResolvedPackageVersionWithMetadata, RetryOptions, defaultOptions, getLatestVersion, getLatestVersionBatch, getVersions, getVersionsBatch, pickRegistry };
package/dist/index.mjs CHANGED
@@ -1,83 +1,42 @@
1
+ //#region ../node_modules/.pnpm/is-network-error@1.3.0/node_modules/is-network-error/index.js
1
2
  const objectToString = Object.prototype.toString;
2
-
3
- const isError = value => objectToString.call(value) === '[object Error]';
4
-
3
+ const isError = (value) => objectToString.call(value) === "[object Error]";
5
4
  const errorMessages = new Set([
6
- 'network error', // Chrome
7
- 'Failed to fetch', // Chrome
8
- 'NetworkError when attempting to fetch resource.', // Firefox
9
- 'The Internet connection appears to be offline.', // Safari 16
10
- 'Network request failed', // `cross-fetch`
11
- 'fetch failed', // Undici (Node.js)
12
- 'terminated', // Undici (Node.js)
13
- ' A network error occurred.', // Bun (WebKit)
14
- 'Network connection lost', // Cloudflare Workers (fetch)
5
+ "network error",
6
+ "Failed to fetch",
7
+ "NetworkError when attempting to fetch resource.",
8
+ "The Internet connection appears to be offline.",
9
+ "Network request failed",
10
+ "fetch failed",
11
+ "terminated",
12
+ " A network error occurred.",
13
+ "Network connection lost"
15
14
  ]);
16
-
17
15
  function isNetworkError(error) {
18
- const isValid = error
19
- && isError(error)
20
- && error.name === 'TypeError'
21
- && typeof error.message === 'string';
22
-
23
- if (!isValid) {
24
- return false;
25
- }
26
-
27
- const {message, stack} = error;
28
-
29
- // Safari 17+ has generic message but no stack for network errors
30
- if (message === 'Load failed') {
31
- return stack === undefined
32
- // Sentry adds its own stack trace to the fetch error, so also check for that
33
- || '__sentry_captured__' in error;
34
- }
35
-
36
- // Deno network errors start with specific text
37
- if (message.startsWith('error sending request for url')) {
38
- return true;
39
- }
40
-
41
- // Standard network error messages
16
+ if (!(error && isError(error) && error.name === "TypeError" && typeof error.message === "string")) return false;
17
+ const { message, stack } = error;
18
+ if (message === "Load failed") return stack === void 0 || "__sentry_captured__" in error;
19
+ if (message.startsWith("error sending request for url")) return true;
42
20
  return errorMessages.has(message);
43
21
  }
44
22
 
23
+ //#endregion
24
+ //#region ../node_modules/.pnpm/p-retry@7.1.1/node_modules/p-retry/index.js
45
25
  function validateRetries(retries) {
46
- if (typeof retries === 'number') {
47
- if (retries < 0) {
48
- throw new TypeError('Expected `retries` to be a non-negative number.');
49
- }
50
-
51
- if (Number.isNaN(retries)) {
52
- throw new TypeError('Expected `retries` to be a valid number or Infinity, got NaN.');
53
- }
54
- } else if (retries !== undefined) {
55
- throw new TypeError('Expected `retries` to be a number or Infinity.');
56
- }
26
+ if (typeof retries === "number") {
27
+ if (retries < 0) throw new TypeError("Expected `retries` to be a non-negative number.");
28
+ if (Number.isNaN(retries)) throw new TypeError("Expected `retries` to be a valid number or Infinity, got NaN.");
29
+ } else if (retries !== void 0) throw new TypeError("Expected `retries` to be a number or Infinity.");
57
30
  }
58
-
59
- function validateNumberOption(name, value, {min = 0, allowInfinity = false} = {}) {
60
- if (value === undefined) {
61
- return;
62
- }
63
-
64
- if (typeof value !== 'number' || Number.isNaN(value)) {
65
- throw new TypeError(`Expected \`${name}\` to be a number${allowInfinity ? ' or Infinity' : ''}.`);
66
- }
67
-
68
- if (!allowInfinity && !Number.isFinite(value)) {
69
- throw new TypeError(`Expected \`${name}\` to be a finite number.`);
70
- }
71
-
72
- if (value < min) {
73
- throw new TypeError(`Expected \`${name}\` to be \u2265 ${min}.`);
74
- }
31
+ function validateNumberOption(name, value, { min = 0, allowInfinity = false } = {}) {
32
+ if (value === void 0) return;
33
+ if (typeof value !== "number" || Number.isNaN(value)) throw new TypeError(`Expected \`${name}\` to be a number${allowInfinity ? " or Infinity" : ""}.`);
34
+ if (!allowInfinity && !Number.isFinite(value)) throw new TypeError(`Expected \`${name}\` to be a finite number.`);
35
+ if (value < min) throw new TypeError(`Expected \`${name}\` to be \u2265 ${min}.`);
75
36
  }
76
-
77
- class AbortError extends Error {
37
+ var AbortError = class extends Error {
78
38
  constructor(message) {
79
39
  super();
80
-
81
40
  if (message instanceof Error) {
82
41
  this.originalError = message;
83
42
  ({message} = message);
@@ -85,159 +44,106 @@ class AbortError extends Error {
85
44
  this.originalError = new Error(message);
86
45
  this.originalError.stack = this.stack;
87
46
  }
88
-
89
- this.name = 'AbortError';
47
+ this.name = "AbortError";
90
48
  this.message = message;
91
49
  }
92
- }
93
-
50
+ };
94
51
  function calculateDelay(retriesConsumed, options) {
95
52
  const attempt = Math.max(1, retriesConsumed + 1);
96
- const random = options.randomize ? (Math.random() + 1) : 1;
97
-
98
- let timeout = Math.round(random * options.minTimeout * (options.factor ** (attempt - 1)));
53
+ const random = options.randomize ? Math.random() + 1 : 1;
54
+ let timeout = Math.round(random * options.minTimeout * options.factor ** (attempt - 1));
99
55
  timeout = Math.min(timeout, options.maxTimeout);
100
-
101
56
  return timeout;
102
57
  }
103
-
104
58
  function calculateRemainingTime(start, max) {
105
- if (!Number.isFinite(max)) {
106
- return max;
107
- }
108
-
59
+ if (!Number.isFinite(max)) return max;
109
60
  return max - (performance.now() - start);
110
61
  }
111
-
112
- async function onAttemptFailure({error, attemptNumber, retriesConsumed, startTime, options}) {
113
- const normalizedError = error instanceof Error
114
- ? error
115
- : new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`);
116
-
117
- if (normalizedError instanceof AbortError) {
118
- throw normalizedError.originalError;
119
- }
120
-
121
- const retriesLeft = Number.isFinite(options.retries)
122
- ? Math.max(0, options.retries - retriesConsumed)
123
- : options.retries;
124
-
62
+ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTime, options }) {
63
+ const normalizedError = error instanceof Error ? error : /* @__PURE__ */ new TypeError(`Non-error was thrown: "${error}". You should only throw errors.`);
64
+ if (normalizedError instanceof AbortError) throw normalizedError.originalError;
65
+ const retriesLeft = Number.isFinite(options.retries) ? Math.max(0, options.retries - retriesConsumed) : options.retries;
125
66
  const maxRetryTime = options.maxRetryTime ?? Number.POSITIVE_INFINITY;
126
-
127
67
  const context = Object.freeze({
128
68
  error: normalizedError,
129
69
  attemptNumber,
130
70
  retriesLeft,
131
- retriesConsumed,
71
+ retriesConsumed
132
72
  });
133
-
134
73
  await options.onFailedAttempt(context);
135
-
136
- if (calculateRemainingTime(startTime, maxRetryTime) <= 0) {
137
- throw normalizedError;
138
- }
139
-
74
+ if (calculateRemainingTime(startTime, maxRetryTime) <= 0) throw normalizedError;
140
75
  const consumeRetry = await options.shouldConsumeRetry(context);
141
-
142
76
  const remainingTime = calculateRemainingTime(startTime, maxRetryTime);
143
-
144
- if (remainingTime <= 0 || retriesLeft <= 0) {
145
- throw normalizedError;
146
- }
147
-
77
+ if (remainingTime <= 0 || retriesLeft <= 0) throw normalizedError;
148
78
  if (normalizedError instanceof TypeError && !isNetworkError(normalizedError)) {
149
- if (consumeRetry) {
150
- throw normalizedError;
151
- }
152
-
79
+ if (consumeRetry) throw normalizedError;
153
80
  options.signal?.throwIfAborted();
154
81
  return false;
155
82
  }
156
-
157
- if (!await options.shouldRetry(context)) {
158
- throw normalizedError;
159
- }
160
-
83
+ if (!await options.shouldRetry(context)) throw normalizedError;
161
84
  if (!consumeRetry) {
162
85
  options.signal?.throwIfAborted();
163
86
  return false;
164
87
  }
165
-
166
88
  const delayTime = calculateDelay(retriesConsumed, options);
167
89
  const finalDelay = Math.min(delayTime, remainingTime);
168
-
169
- if (finalDelay > 0) {
170
- await new Promise((resolve, reject) => {
171
- const onAbort = () => {
172
- clearTimeout(timeoutToken);
173
- options.signal?.removeEventListener('abort', onAbort);
174
- reject(options.signal.reason);
175
- };
176
-
177
- const timeoutToken = setTimeout(() => {
178
- options.signal?.removeEventListener('abort', onAbort);
179
- resolve();
180
- }, finalDelay);
181
-
182
- if (options.unref) {
183
- timeoutToken.unref?.();
184
- }
185
-
186
- options.signal?.addEventListener('abort', onAbort, {once: true});
187
- });
188
- }
189
-
190
90
  options.signal?.throwIfAborted();
191
-
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
+ });
104
+ options.signal?.throwIfAborted();
192
105
  return true;
193
106
  }
194
-
195
107
  async function pRetry(input, options = {}) {
196
- options = {...options};
197
-
108
+ options = { ...options };
198
109
  validateRetries(options.retries);
199
-
200
- if (Object.hasOwn(options, 'forever')) {
201
- throw new Error('The `forever` option is no longer supported. For many use-cases, you can set `retries: Infinity` instead.');
202
- }
203
-
110
+ if (Object.hasOwn(options, "forever")) throw new Error("The `forever` option is no longer supported. For many use-cases, you can set `retries: Infinity` instead.");
204
111
  options.retries ??= 10;
205
112
  options.factor ??= 2;
206
- options.minTimeout ??= 1000;
113
+ options.minTimeout ??= 1e3;
207
114
  options.maxTimeout ??= Number.POSITIVE_INFINITY;
208
115
  options.maxRetryTime ??= Number.POSITIVE_INFINITY;
209
116
  options.randomize ??= false;
210
117
  options.onFailedAttempt ??= () => {};
211
118
  options.shouldRetry ??= () => true;
212
119
  options.shouldConsumeRetry ??= () => true;
213
-
214
- // Validate numeric options and normalize edge cases
215
- validateNumberOption('factor', options.factor, {min: 0, allowInfinity: false});
216
- validateNumberOption('minTimeout', options.minTimeout, {min: 0, allowInfinity: false});
217
- validateNumberOption('maxTimeout', options.maxTimeout, {min: 0, allowInfinity: true});
218
- validateNumberOption('maxRetryTime', options.maxRetryTime, {min: 0, allowInfinity: true});
219
-
220
- // Treat non-positive factor as 1 to avoid zero backoff or negative behavior
221
- if (!(options.factor > 0)) {
222
- options.factor = 1;
223
- }
224
-
120
+ validateNumberOption("factor", options.factor, {
121
+ min: 0,
122
+ allowInfinity: false
123
+ });
124
+ validateNumberOption("minTimeout", options.minTimeout, {
125
+ min: 0,
126
+ allowInfinity: false
127
+ });
128
+ validateNumberOption("maxTimeout", options.maxTimeout, {
129
+ min: 0,
130
+ allowInfinity: true
131
+ });
132
+ validateNumberOption("maxRetryTime", options.maxRetryTime, {
133
+ min: 0,
134
+ allowInfinity: true
135
+ });
136
+ if (!(options.factor > 0)) options.factor = 1;
225
137
  options.signal?.throwIfAborted();
226
-
227
138
  let attemptNumber = 0;
228
139
  let retriesConsumed = 0;
229
140
  const startTime = performance.now();
230
-
231
141
  while (Number.isFinite(options.retries) ? retriesConsumed <= options.retries : true) {
232
142
  attemptNumber++;
233
-
234
143
  try {
235
144
  options.signal?.throwIfAborted();
236
-
237
145
  const result = await input(attemptNumber);
238
-
239
146
  options.signal?.throwIfAborted();
240
-
241
147
  return result;
242
148
  } catch (error) {
243
149
  if (await onAttemptFailure({
@@ -245,107 +151,89 @@ async function pRetry(input, options = {}) {
245
151
  attemptNumber,
246
152
  retriesConsumed,
247
153
  startTime,
248
- options,
249
- })) {
250
- retriesConsumed++;
251
- }
154
+ options
155
+ })) retriesConsumed++;
252
156
  }
253
157
  }
254
-
255
- // Should not reach here, but in case it does, throw an error
256
- throw new Error('Retry attempts exhausted without throwing an error.');
158
+ throw new Error("Retry attempts exhausted without throwing an error.");
257
159
  }
258
160
 
161
+ //#endregion
162
+ //#region src/api.ts
259
163
  const defaultRetryOptions = {
260
- retries: 5,
261
- factor: 2,
262
- minTimeout: 1e3,
263
- maxTimeout: Infinity,
264
- randomize: false
265
- };
266
- const defaultOptions = {
267
- /**
268
- * API endpoint for fetching package versions
269
- *
270
- * @default 'https://npm.antfu.dev/'
271
- */
272
- apiEndpoint: "https://npm.antfu.dev/"
164
+ retries: 5,
165
+ factor: 2,
166
+ minTimeout: 1e3,
167
+ maxTimeout: Infinity,
168
+ randomize: false
273
169
  };
170
+ const defaultOptions = { apiEndpoint: "https://npm.antfu.dev/" };
274
171
  async function getLatestVersionBatch(packages, options = {}) {
275
- const {
276
- apiEndpoint = defaultOptions.apiEndpoint,
277
- fetch: fetchApi = fetch,
278
- throw: throwError = true,
279
- retry = defaultRetryOptions
280
- } = options;
281
- let query = [
282
- options.force ? "force=true" : "",
283
- options.metadata ? "metadata=true" : "",
284
- throwError ? "" : "throw=false"
285
- ].filter(Boolean).join("&");
286
- if (query)
287
- query = `?${query}`;
288
- const fetchFn = () => fetchApi(new URL(packages.join("+") + query, apiEndpoint)).then((r) => r.json());
289
- const retryOptions = typeof retry === "number" ? { ...defaultRetryOptions, retries: retry } : retry;
290
- const data = await (retryOptions === false ? fetchFn() : pRetry(fetchFn, retryOptions));
291
- const list = toArray(data);
292
- return throwError ? throwErrorObject(list) : list;
172
+ const { apiEndpoint = defaultOptions.apiEndpoint, fetch: fetchApi = fetch, throw: throwError = true, retry = defaultRetryOptions } = options;
173
+ let query = [
174
+ options.force ? "force=true" : "",
175
+ options.metadata ? "metadata=true" : "",
176
+ throwError ? "" : "throw=false"
177
+ ].filter(Boolean).join("&");
178
+ if (query) query = `?${query}`;
179
+ const fetchFn = () => fetchApi(new URL(packages.join("+") + query, apiEndpoint)).then((r) => r.json());
180
+ const retryOptions = typeof retry === "number" ? {
181
+ ...defaultRetryOptions,
182
+ retries: retry
183
+ } : retry;
184
+ const list = toArray(await (retryOptions === false ? fetchFn() : pRetry(fetchFn, retryOptions)));
185
+ return throwError ? throwErrorObject(list) : list;
293
186
  }
294
187
  async function getLatestVersion(name, options = {}) {
295
- const [data] = await getLatestVersionBatch([name], options);
296
- return data;
188
+ const [data] = await getLatestVersionBatch([name], options);
189
+ return data;
297
190
  }
298
191
  async function getVersionsBatch(packages, options = {}) {
299
- const {
300
- apiEndpoint = defaultOptions.apiEndpoint,
301
- fetch: fetchApi = fetch,
302
- throw: throwError = true,
303
- retry = defaultRetryOptions
304
- } = options;
305
- let query = [
306
- options.force ? "force=true" : "",
307
- options.loose ? "loose=true" : "",
308
- options.metadata ? "metadata=true" : "",
309
- options.after ? `after=${encodeURIComponent(options.after)}` : "",
310
- throwError ? "" : "throw=false"
311
- ].filter(Boolean).join("&");
312
- if (query)
313
- query = `?${query}`;
314
- const fetchFn = () => fetchApi(new URL(`/versions/${packages.join("+")}${query}`, apiEndpoint)).then((r) => r.json());
315
- const data = await (retry === false ? fetchFn() : pRetry(
316
- fetchFn,
317
- typeof retry === "number" ? { ...defaultRetryOptions, retries: retry } : retry
318
- ));
319
- const list = toArray(data);
320
- return throwError ? throwErrorObject(list) : list;
192
+ const { apiEndpoint = defaultOptions.apiEndpoint, fetch: fetchApi = fetch, throw: throwError = true, retry = defaultRetryOptions } = options;
193
+ let query = [
194
+ options.force ? "force=true" : "",
195
+ options.loose ? "loose=true" : "",
196
+ options.metadata ? "metadata=true" : "",
197
+ options.after ? `after=${encodeURIComponent(options.after)}` : "",
198
+ throwError ? "" : "throw=false"
199
+ ].filter(Boolean).join("&");
200
+ if (query) query = `?${query}`;
201
+ const fetchFn = () => fetchApi(new URL(`/versions/${packages.join("+")}${query}`, apiEndpoint)).then((r) => r.json());
202
+ const list = toArray(await (retry === false ? fetchFn() : pRetry(fetchFn, typeof retry === "number" ? {
203
+ ...defaultRetryOptions,
204
+ retries: retry
205
+ } : retry)));
206
+ return throwError ? throwErrorObject(list) : list;
321
207
  }
322
208
  async function getVersions(name, options = {}) {
323
- const [data] = await getVersionsBatch([name], options);
324
- return data;
209
+ const [data] = await getVersionsBatch([name], options);
210
+ return data;
325
211
  }
326
212
  function throwErrorObject(data) {
327
- for (const item of toArray(data)) {
328
- if (item && "error" in item)
329
- throw new Error(item.message || item.error);
330
- }
331
- return data;
213
+ for (const item of toArray(data)) if (item && "error" in item) throw new Error(item.message || item.error);
214
+ return data;
332
215
  }
333
216
  function toArray(data) {
334
- if (Array.isArray(data))
335
- return data;
336
- return [data];
217
+ if (Array.isArray(data)) return data;
218
+ return [data];
337
219
  }
338
220
 
221
+ //#endregion
222
+ //#region src/helpers.ts
339
223
  const NPM_REGISTRY = "https://registry.npmjs.org/";
224
+ /**
225
+ * Lightweight replacement of `npm-registry-fetch` function `pickRegistry`'
226
+ *
227
+ * @param scope - scope of package, get from 'npm-package-arg'
228
+ * @param npmConfigs - npm configs, read from `.npmrc` file
229
+ * @param defaultRegistry - default registry, default to 'https://registry.npmjs.org/'
230
+ */
340
231
  function pickRegistry(scope, npmConfigs, defaultRegistry = NPM_REGISTRY) {
341
- let registry = scope ? npmConfigs[`${scope.replace(/^@?/, "@")}:registry`] : void 0;
342
- if (!registry && typeof npmConfigs.scope === "string") {
343
- registry = npmConfigs[`${npmConfigs.scope.replace(/^@?/, "@")}:registry`];
344
- }
345
- if (!registry) {
346
- registry = npmConfigs.registry || defaultRegistry;
347
- }
348
- return registry;
232
+ let registry = scope ? npmConfigs[`${scope.replace(/^@?/, "@")}:registry`] : void 0;
233
+ if (!registry && typeof npmConfigs.scope === "string") registry = npmConfigs[`${npmConfigs.scope.replace(/^@?/, "@")}:registry`];
234
+ if (!registry) registry = npmConfigs.registry || defaultRegistry;
235
+ return registry;
349
236
  }
350
237
 
351
- export { NPM_REGISTRY, defaultOptions, getLatestVersion, getLatestVersionBatch, getVersions, getVersionsBatch, pickRegistry };
238
+ //#endregion
239
+ 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.1.0",
4
+ "version": "1.2.1",
5
5
  "description": "Get npm package metadata",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -15,19 +15,19 @@
15
15
  "keywords": [],
16
16
  "sideEffects": false,
17
17
  "exports": {
18
- ".": "./dist/index.mjs"
18
+ ".": "./dist/index.mjs",
19
+ "./package.json": "./package.json"
19
20
  },
20
- "main": "./dist/index.mjs",
21
- "module": "./dist/index.mjs",
22
21
  "types": "./dist/index.d.mts",
23
22
  "files": [
24
23
  "dist"
25
24
  ],
26
25
  "devDependencies": {
27
- "p-retry": "^7.1.0"
26
+ "p-retry": "^7.1.1",
27
+ "tsdown": "^0.20.1"
28
28
  },
29
29
  "scripts": {
30
- "build": "unbuild",
31
- "dev": "unbuild --stub"
30
+ "build": "tsdown",
31
+ "dev": "tsdown --watch"
32
32
  }
33
33
  }