fast-npm-meta 1.0.0 → 1.2.0
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 +150 -94
- package/dist/index.mjs +221 -60
- package/package.json +9 -6
package/dist/index.d.mts
CHANGED
|
@@ -1,125 +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
|
-
|
|
32
|
+
status: number;
|
|
33
|
+
name: string;
|
|
34
|
+
error: string;
|
|
33
35
|
}
|
|
34
36
|
type MaybeError<T> = T | PackageError;
|
|
35
37
|
interface PackageManifestError extends PackageError {
|
|
36
|
-
|
|
38
|
+
lastSynced: number;
|
|
37
39
|
}
|
|
38
40
|
interface ResolvedPackageVersion {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
name: string;
|
|
42
|
+
version: string | null;
|
|
43
|
+
specifier: string;
|
|
44
|
+
publishedAt: string | null;
|
|
45
|
+
lastSynced: number;
|
|
44
46
|
}
|
|
45
|
-
interface ResolvedPackageVersionWithMetadata extends ResolvedPackageVersion, PackageVersionMeta {
|
|
47
|
+
interface ResolvedPackageVersionWithMetadata extends ResolvedPackageVersion, PackageVersionMeta {}
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/types.d.ts
|
|
50
|
+
interface RetryOptions {
|
|
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;
|
|
46
83
|
}
|
|
47
|
-
|
|
48
84
|
interface FetchOptions<Throw extends boolean = true> {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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;
|
|
67
103
|
}
|
|
68
104
|
interface GetVersionsOptions<Metadata extends boolean = false, Throw extends boolean = true> extends FetchOptions<Throw> {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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;
|
|
93
138
|
}
|
|
94
139
|
interface GetLatestVersionOptions<Metadata extends boolean = false, Throw extends boolean = true> extends FetchOptions<Throw> {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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;
|
|
107
161
|
}
|
|
108
162
|
type InferGetVersionsResult<Metadata, Throw> = Metadata extends true ? Throw extends true ? PackageVersionsInfoWithMetadata : MaybeError<PackageVersionsInfoWithMetadata> : Throw extends true ? PackageVersionsInfo : MaybeError<PackageVersionsInfo>;
|
|
109
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
|
|
110
166
|
declare const defaultOptions: {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
167
|
+
/**
|
|
168
|
+
* API endpoint for fetching package versions
|
|
169
|
+
*
|
|
170
|
+
* @default 'https://npm.antfu.dev/'
|
|
171
|
+
*/
|
|
172
|
+
apiEndpoint: string;
|
|
117
173
|
};
|
|
118
174
|
declare function getLatestVersionBatch<Metadata extends boolean = false, Throw extends boolean = true>(packages: string[], options?: GetLatestVersionOptions<Metadata, Throw>): Promise<InferGetLatestVersionResult<Metadata, Throw>[]>;
|
|
119
175
|
declare function getLatestVersion<Metadata extends boolean = false, Throw extends boolean = true>(name: string, options?: GetLatestVersionOptions<Metadata, Throw>): Promise<InferGetLatestVersionResult<Metadata, Throw>>;
|
|
120
176
|
declare function getVersionsBatch<Metadata extends boolean = false, Throw extends boolean = true>(packages: string[], options?: GetVersionsOptions<Metadata, Throw>): Promise<InferGetVersionsResult<Metadata, Throw>[]>;
|
|
121
177
|
declare function getVersions<Metadata extends boolean = false, Throw extends boolean = true>(name: string, options?: GetVersionsOptions<Metadata, Throw>): Promise<InferGetVersionsResult<Metadata, Throw>>;
|
|
122
|
-
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region src/helpers.d.ts
|
|
123
180
|
declare const NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
124
181
|
/**
|
|
125
182
|
* Lightweight replacement of `npm-registry-fetch` function `pickRegistry`'
|
|
@@ -129,6 +186,5 @@ declare const NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
|
129
186
|
* @param defaultRegistry - default registry, default to 'https://registry.npmjs.org/'
|
|
130
187
|
*/
|
|
131
188
|
declare function pickRegistry(scope: string | null | undefined, npmConfigs: Record<string, unknown>, defaultRegistry?: string): string;
|
|
132
|
-
|
|
133
|
-
export { NPM_REGISTRY, defaultOptions, getLatestVersion, getLatestVersionBatch, getVersions, getVersionsBatch, pickRegistry };
|
|
134
|
-
export type { Engines, FetchOptions, GetLatestVersionOptions, GetVersionsOptions, InferGetLatestVersionResult, InferGetVersionsResult, MaybeError, PackageError, PackageManifest, PackageManifestError, PackageVersionMeta, PackageVersionsInfo, PackageVersionsInfoWithMetadata, ResolvedPackageVersion, ResolvedPackageVersionWithMetadata };
|
|
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,78 +1,239 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
//#region ../node_modules/.pnpm/is-network-error@1.3.0/node_modules/is-network-error/index.js
|
|
2
|
+
const objectToString = Object.prototype.toString;
|
|
3
|
+
const isError = (value) => objectToString.call(value) === "[object Error]";
|
|
4
|
+
const errorMessages = new Set([
|
|
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"
|
|
14
|
+
]);
|
|
15
|
+
function isNetworkError(error) {
|
|
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;
|
|
20
|
+
return errorMessages.has(message);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region ../node_modules/.pnpm/p-retry@7.1.1/node_modules/p-retry/index.js
|
|
25
|
+
function validateRetries(retries) {
|
|
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.");
|
|
30
|
+
}
|
|
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}.`);
|
|
36
|
+
}
|
|
37
|
+
var AbortError = class extends Error {
|
|
38
|
+
constructor(message) {
|
|
39
|
+
super();
|
|
40
|
+
if (message instanceof Error) {
|
|
41
|
+
this.originalError = message;
|
|
42
|
+
({message} = message);
|
|
43
|
+
} else {
|
|
44
|
+
this.originalError = new Error(message);
|
|
45
|
+
this.originalError.stack = this.stack;
|
|
46
|
+
}
|
|
47
|
+
this.name = "AbortError";
|
|
48
|
+
this.message = message;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
function calculateDelay(retriesConsumed, options) {
|
|
52
|
+
const attempt = Math.max(1, retriesConsumed + 1);
|
|
53
|
+
const random = options.randomize ? Math.random() + 1 : 1;
|
|
54
|
+
let timeout = Math.round(random * options.minTimeout * options.factor ** (attempt - 1));
|
|
55
|
+
timeout = Math.min(timeout, options.maxTimeout);
|
|
56
|
+
return timeout;
|
|
57
|
+
}
|
|
58
|
+
function calculateRemainingTime(start, max) {
|
|
59
|
+
if (!Number.isFinite(max)) return max;
|
|
60
|
+
return max - (performance.now() - start);
|
|
61
|
+
}
|
|
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;
|
|
66
|
+
const maxRetryTime = options.maxRetryTime ?? Number.POSITIVE_INFINITY;
|
|
67
|
+
const context = Object.freeze({
|
|
68
|
+
error: normalizedError,
|
|
69
|
+
attemptNumber,
|
|
70
|
+
retriesLeft,
|
|
71
|
+
retriesConsumed
|
|
72
|
+
});
|
|
73
|
+
await options.onFailedAttempt(context);
|
|
74
|
+
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
|
+
}
|
|
83
|
+
if (!await options.shouldRetry(context)) throw normalizedError;
|
|
84
|
+
if (!consumeRetry) {
|
|
85
|
+
options.signal?.throwIfAborted();
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
const delayTime = calculateDelay(retriesConsumed, options);
|
|
89
|
+
const finalDelay = Math.min(delayTime, remainingTime);
|
|
90
|
+
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
|
+
});
|
|
104
|
+
options.signal?.throwIfAborted();
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
async function pRetry(input, options = {}) {
|
|
108
|
+
options = { ...options };
|
|
109
|
+
validateRetries(options.retries);
|
|
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.");
|
|
111
|
+
options.retries ??= 10;
|
|
112
|
+
options.factor ??= 2;
|
|
113
|
+
options.minTimeout ??= 1e3;
|
|
114
|
+
options.maxTimeout ??= Number.POSITIVE_INFINITY;
|
|
115
|
+
options.maxRetryTime ??= Number.POSITIVE_INFINITY;
|
|
116
|
+
options.randomize ??= false;
|
|
117
|
+
options.onFailedAttempt ??= () => {};
|
|
118
|
+
options.shouldRetry ??= () => true;
|
|
119
|
+
options.shouldConsumeRetry ??= () => true;
|
|
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;
|
|
137
|
+
options.signal?.throwIfAborted();
|
|
138
|
+
let attemptNumber = 0;
|
|
139
|
+
let retriesConsumed = 0;
|
|
140
|
+
const startTime = performance.now();
|
|
141
|
+
while (Number.isFinite(options.retries) ? retriesConsumed <= options.retries : true) {
|
|
142
|
+
attemptNumber++;
|
|
143
|
+
try {
|
|
144
|
+
options.signal?.throwIfAborted();
|
|
145
|
+
const result = await input(attemptNumber);
|
|
146
|
+
options.signal?.throwIfAborted();
|
|
147
|
+
return result;
|
|
148
|
+
} catch (error) {
|
|
149
|
+
if (await onAttemptFailure({
|
|
150
|
+
error,
|
|
151
|
+
attemptNumber,
|
|
152
|
+
retriesConsumed,
|
|
153
|
+
startTime,
|
|
154
|
+
options
|
|
155
|
+
})) retriesConsumed++;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
throw new Error("Retry attempts exhausted without throwing an error.");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
//#endregion
|
|
162
|
+
//#region src/api.ts
|
|
163
|
+
const defaultRetryOptions = {
|
|
164
|
+
retries: 5,
|
|
165
|
+
factor: 2,
|
|
166
|
+
minTimeout: 1e3,
|
|
167
|
+
maxTimeout: Infinity,
|
|
168
|
+
randomize: false
|
|
8
169
|
};
|
|
170
|
+
const defaultOptions = { apiEndpoint: "https://npm.antfu.dev/" };
|
|
9
171
|
async function getLatestVersionBatch(packages, options = {}) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
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;
|
|
25
186
|
}
|
|
26
187
|
async function getLatestVersion(name, options = {}) {
|
|
27
|
-
|
|
28
|
-
|
|
188
|
+
const [data] = await getLatestVersionBatch([name], options);
|
|
189
|
+
return data;
|
|
29
190
|
}
|
|
30
191
|
async function getVersionsBatch(packages, options = {}) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const list = toArray(data);
|
|
47
|
-
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;
|
|
48
207
|
}
|
|
49
208
|
async function getVersions(name, options = {}) {
|
|
50
|
-
|
|
51
|
-
|
|
209
|
+
const [data] = await getVersionsBatch([name], options);
|
|
210
|
+
return data;
|
|
52
211
|
}
|
|
53
212
|
function throwErrorObject(data) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
throw new Error(item.message || item.error);
|
|
57
|
-
}
|
|
58
|
-
return data;
|
|
213
|
+
for (const item of toArray(data)) if (item && "error" in item) throw new Error(item.message || item.error);
|
|
214
|
+
return data;
|
|
59
215
|
}
|
|
60
216
|
function toArray(data) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return [data];
|
|
217
|
+
if (Array.isArray(data)) return data;
|
|
218
|
+
return [data];
|
|
64
219
|
}
|
|
65
220
|
|
|
221
|
+
//#endregion
|
|
222
|
+
//#region src/helpers.ts
|
|
66
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
|
+
*/
|
|
67
231
|
function pickRegistry(scope, npmConfigs, defaultRegistry = NPM_REGISTRY) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (!registry) {
|
|
73
|
-
registry = npmConfigs.registry || defaultRegistry;
|
|
74
|
-
}
|
|
75
|
-
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;
|
|
76
236
|
}
|
|
77
237
|
|
|
78
|
-
|
|
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.
|
|
4
|
+
"version": "1.2.0",
|
|
5
5
|
"description": "Get npm package metadata",
|
|
6
6
|
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -15,16 +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
|
],
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"p-retry": "^7.1.1",
|
|
27
|
+
"tsdown": "^0.20.1"
|
|
28
|
+
},
|
|
26
29
|
"scripts": {
|
|
27
|
-
"build": "
|
|
28
|
-
"dev": "
|
|
30
|
+
"build": "tsdown",
|
|
31
|
+
"dev": "tsdown --watch"
|
|
29
32
|
}
|
|
30
33
|
}
|