-
-
Notifications
You must be signed in to change notification settings - Fork 424
Expand file tree
/
Copy pathnpm.ts
More file actions
64 lines (59 loc) · 2.01 KB
/
npm.ts
File metadata and controls
64 lines (59 loc) · 2.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import { getLatestVersion } from 'fast-npm-meta'
import { createError } from 'h3'
import validatePackageName from 'validate-npm-package-name'
const NPM_USERNAME_RE = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i
const NPM_USERNAME_MAX_LENGTH = 50
/**
* Encode package name for URL usage.
* Scoped packages need special handling (@scope/name → @scope%2Fname)
*/
export function encodePackageName(name: string): string {
if (name.startsWith('@')) {
return `@${encodeURIComponent(name.slice(1))}`
}
return encodeURIComponent(name)
}
/**
* Fetch the latest version of a package using fast-npm-meta API.
* This is a lightweight alternative to fetching the full packument.
*
* @param name Package name
* @returns Latest version string or null if not found
* @see https://github.com/antfu/fast-npm-meta
*/
export async function fetchLatestVersion(name: string): Promise<string | null> {
try {
const meta = await getLatestVersion(name)
return meta.version
} catch {
return null
}
}
/**
* Validate an npm package name and throw an HTTP error if invalid.
* Uses validate-npm-package-name to check against npm naming rules.
*/
export function assertValidPackageName(name: string): void {
const result = validatePackageName(name)
if (!result.validForNewPackages && !result.validForOldPackages) {
const errors = [...(result.errors ?? []), ...(result.warnings ?? [])]
throw createError({
// TODO: throwing 404 rather than 400 as it's cacheable
statusCode: 404,
message: `Invalid package name: ${errors[0] ?? 'unknown error'}`,
})
}
}
/**
* Validate an npm username and throw an HTTP error if invalid.
* Uses a regular expression to check against npm naming rules.
*/
export function assertValidUsername(username: string): void {
if (!username || username.length > NPM_USERNAME_MAX_LENGTH || !NPM_USERNAME_RE.test(username)) {
throw createError({
// TODO: throwing 404 rather than 400 as it's cacheable
statusCode: 404,
message: `Invalid username: ${username}`,
})
}
}