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.
- package/dist/index.d.mts +149 -146
- package/dist/index.mjs +138 -250
- 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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
29
|
+
specifier: string;
|
|
29
30
|
}
|
|
30
31
|
interface PackageError {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
38
|
+
lastSynced: number;
|
|
38
39
|
}
|
|
39
40
|
interface ResolvedPackageVersion {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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 ===
|
|
47
|
-
if (retries < 0)
|
|
48
|
-
|
|
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
|
-
|
|
60
|
-
if (value
|
|
61
|
-
|
|
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 ?
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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 ??=
|
|
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
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
validateNumberOption(
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
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
|
-
|
|
296
|
-
|
|
188
|
+
const [data] = await getLatestVersionBatch([name], options);
|
|
189
|
+
return data;
|
|
297
190
|
}
|
|
298
191
|
async function getVersionsBatch(packages, options = {}) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
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
|
-
|
|
324
|
-
|
|
209
|
+
const [data] = await getVersionsBatch([name], options);
|
|
210
|
+
return data;
|
|
325
211
|
}
|
|
326
212
|
function throwErrorObject(data) {
|
|
327
|
-
|
|
328
|
-
|
|
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
|
-
|
|
335
|
-
|
|
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
26
|
+
"p-retry": "^7.1.1",
|
|
27
|
+
"tsdown": "^0.20.1"
|
|
28
28
|
},
|
|
29
29
|
"scripts": {
|
|
30
|
-
"build": "
|
|
31
|
-
"dev": "
|
|
30
|
+
"build": "tsdown",
|
|
31
|
+
"dev": "tsdown --watch"
|
|
32
32
|
}
|
|
33
33
|
}
|