depstein 0.1.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.
Files changed (65) hide show
  1. package/README.md +438 -0
  2. package/dist/core/cache.d.ts +15 -0
  3. package/dist/core/cache.js +75 -0
  4. package/dist/core/cache.js.map +1 -0
  5. package/dist/core/fetcher.d.ts +7 -0
  6. package/dist/core/fetcher.js +59 -0
  7. package/dist/core/fetcher.js.map +1 -0
  8. package/dist/core/replacements.d.ts +32 -0
  9. package/dist/core/replacements.js +419 -0
  10. package/dist/core/replacements.js.map +1 -0
  11. package/dist/core/scanner.d.ts +7 -0
  12. package/dist/core/scanner.js +298 -0
  13. package/dist/core/scanner.js.map +1 -0
  14. package/dist/core/scorer.d.ts +5 -0
  15. package/dist/core/scorer.js +289 -0
  16. package/dist/core/scorer.js.map +1 -0
  17. package/dist/core/types.d.ts +99 -0
  18. package/dist/core/types.js +2 -0
  19. package/dist/core/types.js.map +1 -0
  20. package/dist/core/vulnerabilities.d.ts +5 -0
  21. package/dist/core/vulnerabilities.js +93 -0
  22. package/dist/core/vulnerabilities.js.map +1 -0
  23. package/dist/ecosystems/cargo.d.ts +2 -0
  24. package/dist/ecosystems/cargo.js +74 -0
  25. package/dist/ecosystems/cargo.js.map +1 -0
  26. package/dist/ecosystems/golang.d.ts +2 -0
  27. package/dist/ecosystems/golang.js +90 -0
  28. package/dist/ecosystems/golang.js.map +1 -0
  29. package/dist/ecosystems/npm.d.ts +2 -0
  30. package/dist/ecosystems/npm.js +92 -0
  31. package/dist/ecosystems/npm.js.map +1 -0
  32. package/dist/ecosystems/pypi.d.ts +2 -0
  33. package/dist/ecosystems/pypi.js +80 -0
  34. package/dist/ecosystems/pypi.js.map +1 -0
  35. package/dist/index.d.ts +2 -0
  36. package/dist/index.js +303 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/tui/colors.d.ts +17 -0
  39. package/dist/tui/colors.js +86 -0
  40. package/dist/tui/colors.js.map +1 -0
  41. package/dist/tui/dashboard.d.ts +7 -0
  42. package/dist/tui/dashboard.js +236 -0
  43. package/dist/tui/dashboard.js.map +1 -0
  44. package/dist/tui/detail.d.ts +6 -0
  45. package/dist/tui/detail.js +68 -0
  46. package/dist/tui/detail.js.map +1 -0
  47. package/dist/tui/picker.d.ts +7 -0
  48. package/dist/tui/picker.js +62 -0
  49. package/dist/tui/picker.js.map +1 -0
  50. package/dist/tui/summary.d.ts +6 -0
  51. package/dist/tui/summary.js +13 -0
  52. package/dist/tui/summary.js.map +1 -0
  53. package/dist/tui/table.d.ts +9 -0
  54. package/dist/tui/table.js +50 -0
  55. package/dist/tui/table.js.map +1 -0
  56. package/dist/utils/format.d.ts +9 -0
  57. package/dist/utils/format.js +72 -0
  58. package/dist/utils/format.js.map +1 -0
  59. package/dist/utils/http.d.ts +2 -0
  60. package/dist/utils/http.js +53 -0
  61. package/dist/utils/http.js.map +1 -0
  62. package/dist/utils/spinner.d.ts +11 -0
  63. package/dist/utils/spinner.js +40 -0
  64. package/dist/utils/spinner.js.map +1 -0
  65. package/package.json +50 -0
@@ -0,0 +1,99 @@
1
+ export type Ecosystem = 'npm' | 'pypi' | 'cargo' | 'golang';
2
+ export type Grade = 'A' | 'B' | 'C' | 'D' | 'F';
3
+ export type FilterMode = 'all' | 'critical' | 'poor' | 'dev' | 'prod';
4
+ export type SortMode = 'score' | 'name' | 'size' | 'updated';
5
+ export type SeverityLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
6
+ export interface RawDependency {
7
+ name: string;
8
+ version: string;
9
+ ecosystem: Ecosystem;
10
+ isDev: boolean;
11
+ }
12
+ export interface Vulnerability {
13
+ id: string;
14
+ summary: string;
15
+ severity: SeverityLevel;
16
+ aliases: string[];
17
+ }
18
+ export interface PackageMetadata {
19
+ name: string;
20
+ ecosystem: Ecosystem;
21
+ latestVersion: string;
22
+ requestedVersion: string;
23
+ publishedAt: Date | null;
24
+ description: string;
25
+ license: string;
26
+ repositoryUrl: string | null;
27
+ weeklyDownloads: number | null;
28
+ monthlyDownloads: number | null;
29
+ totalDownloads: number | null;
30
+ unpackedSize: number | null;
31
+ gzipSize: number | null;
32
+ minifiedSize: number | null;
33
+ hasBuiltinTypes: boolean;
34
+ hasTypesPackage: boolean;
35
+ vulnerabilities: Vulnerability[];
36
+ fromCache: boolean;
37
+ fetchError: string | null;
38
+ }
39
+ export interface ScoreDimension {
40
+ name: string;
41
+ score: number;
42
+ maxScore: number;
43
+ reason: string;
44
+ }
45
+ export interface ScoredDependency {
46
+ raw: RawDependency;
47
+ metadata: PackageMetadata;
48
+ dimensions: {
49
+ maintenance: ScoreDimension;
50
+ popularity: ScoreDimension;
51
+ bundleSize: ScoreDimension;
52
+ typescript: ScoreDimension;
53
+ license: ScoreDimension;
54
+ vulnerability: ScoreDimension;
55
+ };
56
+ totalScore: number;
57
+ grade: Grade;
58
+ issues: string[];
59
+ suggestion: string | null;
60
+ }
61
+ export interface ScanResult {
62
+ projectPath: string;
63
+ ecosystem: Ecosystem;
64
+ dependencies: RawDependency[];
65
+ }
66
+ export interface AuditResult {
67
+ projectPath: string;
68
+ ecosystem: Ecosystem;
69
+ scoredDependencies: ScoredDependency[];
70
+ averageScore: number;
71
+ grade: Grade;
72
+ totalCount: number;
73
+ criticalCount: number;
74
+ poorCount: number;
75
+ fairCount: number;
76
+ goodCount: number;
77
+ excellentCount: number;
78
+ timestamp: string;
79
+ }
80
+ export interface CLIOptions {
81
+ path: string;
82
+ ecosystem?: Ecosystem;
83
+ filter: FilterMode;
84
+ sort: SortMode;
85
+ noCache: boolean;
86
+ json: boolean;
87
+ top?: number;
88
+ fix: boolean;
89
+ minScore?: number;
90
+ ci: boolean;
91
+ }
92
+ export type CachedMetadata = Omit<PackageMetadata, 'fromCache'> & {
93
+ publishedAt: string | null;
94
+ };
95
+ export interface CacheEntry {
96
+ data: CachedMetadata;
97
+ timestamp: number;
98
+ }
99
+ export type CacheStore = Record<string, CacheEntry>;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import type { Vulnerability, Ecosystem } from './types.js';
2
+ export declare function fetchVulnerabilities(name: string, ecosystem: Ecosystem,
3
+ /** Resolved/installed version — enables version-aware filtering so only
4
+ * vulns that affect THIS version are returned (not all historical CVEs). */
5
+ version?: string | null): Promise<Vulnerability[]>;
@@ -0,0 +1,93 @@
1
+ import { fetchJson } from '../utils/http.js';
2
+ /**
3
+ * Ecosystem name mappings for OSV API
4
+ * https://osv.dev/docs/#section/Background
5
+ */
6
+ const OSV_ECOSYSTEM = {
7
+ npm: 'npm',
8
+ pypi: 'PyPI',
9
+ cargo: 'crates.io',
10
+ golang: 'Go',
11
+ };
12
+ /** Map a CVSS numeric base score (0–10) to our severity tiers. */
13
+ function cvssScoreToSeverity(score) {
14
+ if (score >= 9.0)
15
+ return 'CRITICAL';
16
+ if (score >= 7.0)
17
+ return 'HIGH';
18
+ if (score >= 4.0)
19
+ return 'MEDIUM';
20
+ return 'LOW';
21
+ }
22
+ /**
23
+ * Resolve severity using a three-tier strategy:
24
+ * 1. Explicit string from database_specific.severity (GitHub Advisory / NVD)
25
+ * 2. Numeric CVSS score from database_specific.cvss.score
26
+ * 3. ecosystem_specific.severity string
27
+ * 4. Fall back to LOW (conservative unknown)
28
+ */
29
+ function resolveSeverity(v) {
30
+ // Tier 1: string severity from authoritative database fields
31
+ for (const raw of [v.database_specific?.severity, v.ecosystem_specific?.severity]) {
32
+ if (!raw)
33
+ continue;
34
+ const s = raw.toUpperCase();
35
+ if (s === 'CRITICAL')
36
+ return 'CRITICAL';
37
+ if (s === 'HIGH')
38
+ return 'HIGH';
39
+ if (s === 'MEDIUM' || s === 'MODERATE')
40
+ return 'MEDIUM';
41
+ if (s === 'LOW')
42
+ return 'LOW';
43
+ }
44
+ // Tier 2: numeric CVSS score
45
+ const cvssScore = v.database_specific?.cvss?.score;
46
+ if (cvssScore != null && cvssScore > 0) {
47
+ return cvssScoreToSeverity(cvssScore);
48
+ }
49
+ return 'LOW';
50
+ }
51
+ /**
52
+ * Returns true if the version string looks like a concrete resolved version
53
+ * (i.e. not a semver range like ^1.0, ~1.0, >=1.0, etc.)
54
+ */
55
+ function isConcreteVersion(version) {
56
+ return /^\d+\.\d+/.test(version);
57
+ }
58
+ export async function fetchVulnerabilities(name, ecosystem,
59
+ /** Resolved/installed version — enables version-aware filtering so only
60
+ * vulns that affect THIS version are returned (not all historical CVEs). */
61
+ version = null) {
62
+ try {
63
+ const pkgQuery = {
64
+ name,
65
+ ecosystem: OSV_ECOSYSTEM[ecosystem],
66
+ };
67
+ const body = { package: pkgQuery };
68
+ // Pass the concrete installed version so OSV returns only CVEs that
69
+ // affect the version the user actually has installed. Range selectors
70
+ // (^, ~, >) are not valid OSV version strings — skip them.
71
+ if (version && isConcreteVersion(version)) {
72
+ body.version = version;
73
+ }
74
+ const res = (await fetchJson('https://api.osv.dev/v1/query', {
75
+ method: 'POST',
76
+ headers: { 'Content-Type': 'application/json' },
77
+ body: JSON.stringify(body),
78
+ }));
79
+ if (!res.vulns || !Array.isArray(res.vulns))
80
+ return [];
81
+ return res.vulns.slice(0, 20).map(v => ({
82
+ id: v.id,
83
+ summary: v.summary ?? 'No description available',
84
+ severity: resolveSeverity(v),
85
+ aliases: v.aliases ?? [],
86
+ }));
87
+ }
88
+ catch {
89
+ // Never let vulnerability check crash the whole audit
90
+ return [];
91
+ }
92
+ }
93
+ //# sourceMappingURL=vulnerabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vulnerabilities.js","sourceRoot":"","sources":["../../src/core/vulnerabilities.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { PackageMetadata } from '../core/types.js';
2
+ export declare function fetchCargo(name: string, requestedVersion: string, noCache: boolean): Promise<PackageMetadata>;
@@ -0,0 +1,74 @@
1
+ import { fetchJson } from '../utils/http.js';
2
+ import { cache } from '../core/cache.js';
3
+ import { fetchVulnerabilities } from '../core/vulnerabilities.js';
4
+ export async function fetchCargo(name, requestedVersion, noCache) {
5
+ if (!noCache) {
6
+ const cached = cache.get('cargo', name);
7
+ if (cached)
8
+ return { ...cached, fromCache: true };
9
+ }
10
+ try {
11
+ const data = (await fetchJson(`https://crates.io/api/v1/crates/${encodeURIComponent(name)}`, {
12
+ headers: {
13
+ // crates.io requires a descriptive User-Agent
14
+ 'User-Agent': 'depstein/0.1.0 (https://github.com/kstij/DepStein)',
15
+ },
16
+ }));
17
+ if (!data.crate) {
18
+ throw new Error(`Crate "${name}" not found on crates.io`);
19
+ }
20
+ const krate = data.crate;
21
+ const latestVersion = krate.newest_version;
22
+ // Extract license from the matching version entry
23
+ const versionEntry = data.versions?.find(v => v.num === latestVersion);
24
+ const license = versionEntry?.license ?? 'Unknown';
25
+ const updatedAt = versionEntry?.updated_at ?? krate.updated_at;
26
+ const vulnerabilities = await fetchVulnerabilities(name, 'cargo', latestVersion);
27
+ const metadata = {
28
+ name,
29
+ ecosystem: 'cargo',
30
+ latestVersion,
31
+ requestedVersion,
32
+ publishedAt: updatedAt ? new Date(updatedAt) : null,
33
+ description: krate.description ?? '',
34
+ license,
35
+ repositoryUrl: krate.repository ?? krate.homepage ?? krate.documentation ?? null,
36
+ weeklyDownloads: null,
37
+ monthlyDownloads: null,
38
+ totalDownloads: krate.downloads,
39
+ unpackedSize: null,
40
+ gzipSize: null,
41
+ minifiedSize: null,
42
+ hasBuiltinTypes: false,
43
+ hasTypesPackage: false,
44
+ vulnerabilities,
45
+ fetchError: null,
46
+ };
47
+ cache.set('cargo', name, metadata);
48
+ return { ...metadata, fromCache: false };
49
+ }
50
+ catch (err) {
51
+ return {
52
+ name,
53
+ ecosystem: 'cargo',
54
+ latestVersion: requestedVersion,
55
+ requestedVersion,
56
+ publishedAt: null,
57
+ description: '',
58
+ license: 'Unknown',
59
+ repositoryUrl: null,
60
+ weeklyDownloads: null,
61
+ monthlyDownloads: null,
62
+ totalDownloads: null,
63
+ unpackedSize: null,
64
+ gzipSize: null,
65
+ minifiedSize: null,
66
+ hasBuiltinTypes: false,
67
+ hasTypesPackage: false,
68
+ vulnerabilities: [],
69
+ fromCache: false,
70
+ fetchError: err.message,
71
+ };
72
+ }
73
+ }
74
+ //# sourceMappingURL=cargo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cargo.js","sourceRoot":"","sources":["../../src/ecosystems/cargo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { PackageMetadata } from '../core/types.js';
2
+ export declare function fetchGolang(name: string, requestedVersion: string, noCache: boolean): Promise<PackageMetadata>;
@@ -0,0 +1,90 @@
1
+ import { fetchJson } from '../utils/http.js';
2
+ import { cache } from '../core/cache.js';
3
+ import { fetchVulnerabilities } from '../core/vulnerabilities.js';
4
+ function extractGithubPath(module) {
5
+ const m = module.match(/^github\.com\/([^/]+\/[^/]+)/);
6
+ return m ? m[1] : null;
7
+ }
8
+ export async function fetchGolang(name, requestedVersion, noCache) {
9
+ if (!noCache) {
10
+ const cached = cache.get('golang', name);
11
+ if (cached)
12
+ return { ...cached, fromCache: true };
13
+ }
14
+ try {
15
+ // URL-encode the module path for the proxy: '@' and '/' need special handling
16
+ const encodedModule = name
17
+ .split('/')
18
+ .map(s => encodeURIComponent(s))
19
+ .join('/');
20
+ // Fetch latest version info from Go module proxy
21
+ const proxyResult = await fetchJson(`https://proxy.golang.org/${encodedModule}/@latest`).catch(() => null);
22
+ const specificResult = requestedVersion && requestedVersion !== 'latest'
23
+ ? await fetchJson(`https://proxy.golang.org/${encodedModule}/@v/${encodeURIComponent(requestedVersion)}.info`).catch(() => null)
24
+ : null;
25
+ const latestVersion = proxyResult?.Version ?? specificResult?.version ?? requestedVersion;
26
+ const rawTime = proxyResult?.Time ?? specificResult?.time ?? null;
27
+ const publishedAt = rawTime ? new Date(rawTime) : null;
28
+ // Try GitHub API for richer metadata
29
+ let description = '';
30
+ let license = 'Unknown';
31
+ let repositoryUrl = null;
32
+ const githubPath = extractGithubPath(name);
33
+ if (githubPath) {
34
+ repositoryUrl = `https://github.com/${githubPath}`;
35
+ const ghResult = await fetchJson(`https://api.github.com/repos/${githubPath}`).catch(() => null);
36
+ if (ghResult) {
37
+ description = ghResult.description ?? '';
38
+ license = ghResult.license?.spdx_id ?? ghResult.license?.name ?? 'Unknown';
39
+ repositoryUrl = ghResult.html_url ?? repositoryUrl;
40
+ }
41
+ }
42
+ const vulnerabilities = await fetchVulnerabilities(name, 'golang', latestVersion);
43
+ const metadata = {
44
+ name,
45
+ ecosystem: 'golang',
46
+ latestVersion,
47
+ requestedVersion,
48
+ publishedAt,
49
+ description,
50
+ license,
51
+ repositoryUrl,
52
+ weeklyDownloads: null,
53
+ monthlyDownloads: null,
54
+ totalDownloads: null,
55
+ unpackedSize: null,
56
+ gzipSize: null,
57
+ minifiedSize: null,
58
+ hasBuiltinTypes: false,
59
+ hasTypesPackage: false,
60
+ vulnerabilities,
61
+ fetchError: null,
62
+ };
63
+ cache.set('golang', name, metadata);
64
+ return { ...metadata, fromCache: false };
65
+ }
66
+ catch (err) {
67
+ return {
68
+ name,
69
+ ecosystem: 'golang',
70
+ latestVersion: requestedVersion,
71
+ requestedVersion,
72
+ publishedAt: null,
73
+ description: '',
74
+ license: 'Unknown',
75
+ repositoryUrl: null,
76
+ weeklyDownloads: null,
77
+ monthlyDownloads: null,
78
+ totalDownloads: null,
79
+ unpackedSize: null,
80
+ gzipSize: null,
81
+ minifiedSize: null,
82
+ hasBuiltinTypes: false,
83
+ hasTypesPackage: false,
84
+ vulnerabilities: [],
85
+ fromCache: false,
86
+ fetchError: err.message,
87
+ };
88
+ }
89
+ }
90
+ //# sourceMappingURL=golang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"golang.js","sourceRoot":"","sources":["../../src/ecosystems/golang.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { PackageMetadata } from '../core/types.js';
2
+ export declare function fetchNpm(name: string, requestedVersion: string, noCache: boolean): Promise<PackageMetadata>;
@@ -0,0 +1,92 @@
1
+ import { fetchJson } from '../utils/http.js';
2
+ import { cache } from '../core/cache.js';
3
+ import { fetchVulnerabilities } from '../core/vulnerabilities.js';
4
+ import { fetchHead } from '../utils/http.js';
5
+ export async function fetchNpm(name, requestedVersion, noCache) {
6
+ if (!noCache) {
7
+ const cached = cache.get('npm', name);
8
+ if (cached)
9
+ return { ...cached, fromCache: true };
10
+ }
11
+ try {
12
+ const encodedName = encodeURIComponent(name).replace('%40', '@');
13
+ const [registryResult, downloadsResult] = await Promise.allSettled([
14
+ fetchJson(`https://registry.npmjs.org/${encodedName}`),
15
+ fetchJson(`https://api.npmjs.org/downloads/point/last-week/${encodedName}`),
16
+ ]);
17
+ if (registryResult.status === 'rejected') {
18
+ throw new Error(String(registryResult.reason));
19
+ }
20
+ const registry = registryResult.value;
21
+ const downloads = downloadsResult.status === 'fulfilled' ? downloadsResult.value : null;
22
+ const latestVersion = registry['dist-tags']?.latest ?? requestedVersion;
23
+ const versionData = registry.versions?.[latestVersion] ?? {};
24
+ const publishedAt = registry.time?.[latestVersion] ? new Date(registry.time[latestVersion]) : null;
25
+ const hasBuiltinTypes = !!(versionData.types || versionData.typings);
26
+ // Check for @types/{name} on npm (strip scope prefix for scoped packages)
27
+ const unscoped = name.startsWith('@') ? name.split('/')[1] : name;
28
+ const hasTypesPackage = hasBuiltinTypes
29
+ ? false
30
+ : await fetchHead(`https://registry.npmjs.org/@types%2F${encodeURIComponent(unscoped ?? name)}`);
31
+ const rawRepo = versionData.repository?.url ?? registry.repository?.url ?? null;
32
+ const repositoryUrl = rawRepo
33
+ ? rawRepo.replace(/^git\+/, '').replace(/\.git$/, '')
34
+ : null;
35
+ // Fetch real bundle sizes from bundlephobia (minified + gzip).
36
+ // Bundlephobia gives the actual browser-visible weight, which is far
37
+ // smaller than npm's unpackedSize (total extracted file bytes).
38
+ const bundleResult = await fetchJson(`https://bundlephobia.com/api/size?package=${encodedName}@${latestVersion}`).catch(() => null);
39
+ const gzipSize = bundleResult?.gzip ?? null;
40
+ const minifiedSize = bundleResult?.size ?? null;
41
+ const vulnerabilities = await fetchVulnerabilities(name, 'npm', latestVersion);
42
+ const metadata = {
43
+ name,
44
+ ecosystem: 'npm',
45
+ latestVersion,
46
+ requestedVersion,
47
+ publishedAt,
48
+ description: registry.description ?? '',
49
+ license: versionData.license ?? registry.license ?? 'Unknown',
50
+ repositoryUrl,
51
+ weeklyDownloads: downloads?.downloads ?? null,
52
+ monthlyDownloads: null,
53
+ totalDownloads: null,
54
+ unpackedSize: versionData.dist?.unpackedSize ?? null,
55
+ gzipSize,
56
+ minifiedSize,
57
+ hasBuiltinTypes,
58
+ hasTypesPackage,
59
+ vulnerabilities,
60
+ fetchError: null,
61
+ };
62
+ cache.set('npm', name, metadata);
63
+ return { ...metadata, fromCache: false };
64
+ }
65
+ catch (err) {
66
+ return failedMetadata(name, 'npm', requestedVersion, err.message);
67
+ }
68
+ }
69
+ function failedMetadata(name, ecosystem, requestedVersion, error) {
70
+ return {
71
+ name,
72
+ ecosystem,
73
+ latestVersion: requestedVersion,
74
+ requestedVersion,
75
+ publishedAt: null,
76
+ description: '',
77
+ license: 'Unknown',
78
+ repositoryUrl: null,
79
+ weeklyDownloads: null,
80
+ monthlyDownloads: null,
81
+ totalDownloads: null,
82
+ unpackedSize: null,
83
+ gzipSize: null,
84
+ minifiedSize: null,
85
+ hasBuiltinTypes: false,
86
+ hasTypesPackage: false,
87
+ vulnerabilities: [],
88
+ fromCache: false,
89
+ fetchError: error,
90
+ };
91
+ }
92
+ //# sourceMappingURL=npm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"npm.js","sourceRoot":"","sources":["../../src/ecosystems/npm.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { PackageMetadata } from '../core/types.js';
2
+ export declare function fetchPypi(name: string, requestedVersion: string, noCache: boolean): Promise<PackageMetadata>;
@@ -0,0 +1,80 @@
1
+ import { fetchJson } from '../utils/http.js';
2
+ import { cache } from '../core/cache.js';
3
+ import { fetchVulnerabilities } from '../core/vulnerabilities.js';
4
+ export async function fetchPypi(name, requestedVersion, noCache) {
5
+ if (!noCache) {
6
+ const cached = cache.get('pypi', name);
7
+ if (cached)
8
+ return { ...cached, fromCache: true };
9
+ }
10
+ try {
11
+ const [infoResult, statsResult] = await Promise.allSettled([
12
+ fetchJson(`https://pypi.org/pypi/${encodeURIComponent(name)}/json`),
13
+ fetchJson(`https://pypistats.org/api/packages/${encodeURIComponent(name.toLowerCase())}/recent`),
14
+ ]);
15
+ if (infoResult.status === 'rejected') {
16
+ throw new Error(String(infoResult.reason));
17
+ }
18
+ const pkg = infoResult.value;
19
+ const stats = statsResult.status === 'fulfilled' ? statsResult.value : null;
20
+ const latestVersion = pkg.info.version;
21
+ const latestReleases = pkg.releases?.[latestVersion] ?? pkg.urls ?? [];
22
+ const lastRelease = latestReleases[latestReleases.length - 1];
23
+ const publishedAt = lastRelease?.upload_time ? new Date(lastRelease.upload_time + 'Z') : null;
24
+ const urls = pkg.info.project_urls ?? {};
25
+ const repositoryUrl = urls['Source Code'] ??
26
+ urls['Source'] ??
27
+ urls['Repository'] ??
28
+ urls['GitHub'] ??
29
+ urls['Homepage'] ??
30
+ pkg.info.home_page ??
31
+ null;
32
+ const vulnerabilities = await fetchVulnerabilities(name, 'pypi', latestVersion);
33
+ const metadata = {
34
+ name,
35
+ ecosystem: 'pypi',
36
+ latestVersion,
37
+ requestedVersion,
38
+ publishedAt,
39
+ description: pkg.info.summary ?? '',
40
+ license: pkg.info.license ?? 'Unknown',
41
+ repositoryUrl,
42
+ weeklyDownloads: null,
43
+ monthlyDownloads: stats?.data?.last_month ?? null,
44
+ totalDownloads: null,
45
+ unpackedSize: null,
46
+ gzipSize: null,
47
+ minifiedSize: null,
48
+ hasBuiltinTypes: false,
49
+ hasTypesPackage: false,
50
+ vulnerabilities,
51
+ fetchError: null,
52
+ };
53
+ cache.set('pypi', name, metadata);
54
+ return { ...metadata, fromCache: false };
55
+ }
56
+ catch (err) {
57
+ return {
58
+ name,
59
+ ecosystem: 'pypi',
60
+ latestVersion: requestedVersion,
61
+ requestedVersion,
62
+ publishedAt: null,
63
+ description: '',
64
+ license: 'Unknown',
65
+ repositoryUrl: null,
66
+ weeklyDownloads: null,
67
+ monthlyDownloads: null,
68
+ totalDownloads: null,
69
+ unpackedSize: null,
70
+ gzipSize: null,
71
+ minifiedSize: null,
72
+ hasBuiltinTypes: false,
73
+ hasTypesPackage: false,
74
+ vulnerabilities: [],
75
+ fromCache: false,
76
+ fetchError: err.message,
77
+ };
78
+ }
79
+ }
80
+ //# sourceMappingURL=pypi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pypi.js","sourceRoot":"","sources":["../../src/ecosystems/pypi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};