ruckup 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/dist/cli.d.ts +6 -0
  2. package/dist/cli.d.ts.map +1 -0
  3. package/dist/cli.js +323 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/dep-diff.d.ts +9 -0
  6. package/dist/dep-diff.d.ts.map +1 -0
  7. package/dist/dep-diff.js +50 -0
  8. package/dist/dep-diff.js.map +1 -0
  9. package/dist/doctor.d.ts +12 -0
  10. package/dist/doctor.d.ts.map +1 -0
  11. package/dist/doctor.js +102 -0
  12. package/dist/doctor.js.map +1 -0
  13. package/dist/engine.d.ts +14 -0
  14. package/dist/engine.d.ts.map +1 -0
  15. package/dist/engine.js +128 -0
  16. package/dist/engine.js.map +1 -0
  17. package/dist/filter.d.ts +13 -0
  18. package/dist/filter.d.ts.map +1 -0
  19. package/dist/filter.js +68 -0
  20. package/dist/filter.js.map +1 -0
  21. package/dist/format.d.ts +11 -0
  22. package/dist/format.d.ts.map +1 -0
  23. package/dist/format.js +255 -0
  24. package/dist/format.js.map +1 -0
  25. package/dist/index.d.ts +17 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +16 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/inline-diff.d.ts +9 -0
  30. package/dist/inline-diff.d.ts.map +1 -0
  31. package/dist/inline-diff.js +88 -0
  32. package/dist/inline-diff.js.map +1 -0
  33. package/dist/interactive.d.ts +13 -0
  34. package/dist/interactive.d.ts.map +1 -0
  35. package/dist/interactive.js +231 -0
  36. package/dist/interactive.js.map +1 -0
  37. package/dist/open.d.ts +15 -0
  38. package/dist/open.d.ts.map +1 -0
  39. package/dist/open.js +52 -0
  40. package/dist/open.js.map +1 -0
  41. package/dist/package.d.ts +32 -0
  42. package/dist/package.d.ts.map +1 -0
  43. package/dist/package.js +143 -0
  44. package/dist/package.js.map +1 -0
  45. package/dist/registry.d.ts +26 -0
  46. package/dist/registry.d.ts.map +1 -0
  47. package/dist/registry.js +164 -0
  48. package/dist/registry.js.map +1 -0
  49. package/dist/release-info.d.ts +40 -0
  50. package/dist/release-info.d.ts.map +1 -0
  51. package/dist/release-info.js +165 -0
  52. package/dist/release-info.js.map +1 -0
  53. package/dist/security.d.ts +10 -0
  54. package/dist/security.d.ts.map +1 -0
  55. package/dist/security.js +72 -0
  56. package/dist/security.js.map +1 -0
  57. package/dist/types.d.ts +168 -0
  58. package/dist/types.d.ts.map +1 -0
  59. package/dist/types.js +50 -0
  60. package/dist/types.js.map +1 -0
  61. package/dist/version.d.ts +23 -0
  62. package/dist/version.d.ts.map +1 -0
  63. package/dist/version.js +229 -0
  64. package/dist/version.js.map +1 -0
  65. package/package.json +66 -0
@@ -0,0 +1,26 @@
1
+ /**
2
+ * npm registry HTTP client with caching, concurrency, and retry support.
3
+ */
4
+ import type { NpmPackageMetadata, RuckupOptions } from './types.js';
5
+ export declare class RegistryClient {
6
+ private options;
7
+ private limiter;
8
+ private memoryCache;
9
+ private diskCache;
10
+ private diskCacheLoaded;
11
+ constructor(options: RuckupOptions);
12
+ /** Fetch full metadata for a package from the registry */
13
+ fetchPackageMetadata(packageName: string): Promise<NpmPackageMetadata>;
14
+ /** Fetch metadata for multiple packages concurrently */
15
+ fetchMany(packageNames: string[]): Promise<Map<string, NpmPackageMetadata>>;
16
+ /** Clear the disk cache */
17
+ clearCache(): Promise<void>;
18
+ private fetchWithRetry;
19
+ private buildUrl;
20
+ private buildHeaders;
21
+ private resolveCachePath;
22
+ private loadDiskCache;
23
+ private getDiskCacheEntry;
24
+ private setDiskCacheEntry;
25
+ }
26
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAWpE,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,eAAe,CAAS;gBAEpB,OAAO,EAAE,aAAa;IAKlC,0DAA0D;IACpD,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA0B5E,wDAAwD;IAClD,SAAS,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAiBjF,2BAA2B;IACrB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAWnB,cAAc;IAoC5B,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,gBAAgB;YAKV,aAAa;YAcb,iBAAiB;YAcjB,iBAAiB;CAehC"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * npm registry HTTP client with caching, concurrency, and retry support.
3
+ */
4
+ import { homedir } from 'node:os';
5
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
6
+ import { dirname, resolve } from 'node:path';
7
+ import pLimit from 'p-limit';
8
+ export class RegistryClient {
9
+ options;
10
+ limiter;
11
+ memoryCache = new Map();
12
+ diskCache = null;
13
+ diskCacheLoaded = false;
14
+ constructor(options) {
15
+ this.options = options;
16
+ this.limiter = pLimit(options.concurrency);
17
+ }
18
+ /** Fetch full metadata for a package from the registry */
19
+ async fetchPackageMetadata(packageName) {
20
+ // Check memory cache
21
+ const cached = this.memoryCache.get(packageName);
22
+ if (cached)
23
+ return cached;
24
+ // Check disk cache
25
+ if (this.options.cache) {
26
+ const diskCached = await this.getDiskCacheEntry(packageName);
27
+ if (diskCached) {
28
+ this.memoryCache.set(packageName, diskCached);
29
+ return diskCached;
30
+ }
31
+ }
32
+ // Fetch from registry with concurrency limiting
33
+ const data = await this.limiter(() => this.fetchWithRetry(packageName));
34
+ this.memoryCache.set(packageName, data);
35
+ // Store to disk cache
36
+ if (this.options.cache) {
37
+ await this.setDiskCacheEntry(packageName, data);
38
+ }
39
+ return data;
40
+ }
41
+ /** Fetch metadata for multiple packages concurrently */
42
+ async fetchMany(packageNames) {
43
+ const results = new Map();
44
+ const promises = packageNames.map(async (name) => {
45
+ try {
46
+ const data = await this.fetchPackageMetadata(name);
47
+ results.set(name, data);
48
+ }
49
+ catch (err) {
50
+ // Store null-ish so caller can detect failures
51
+ if (this.options.loglevel !== 'silent') {
52
+ console.error(`Failed to fetch ${name}: ${err.message}`);
53
+ }
54
+ }
55
+ });
56
+ await Promise.all(promises);
57
+ return results;
58
+ }
59
+ /** Clear the disk cache */
60
+ async clearCache() {
61
+ const cachePath = this.resolveCachePath();
62
+ try {
63
+ await writeFile(cachePath, '{}', 'utf-8');
64
+ }
65
+ catch {
66
+ // Ignore if cache file doesn't exist
67
+ }
68
+ this.diskCache = {};
69
+ this.memoryCache.clear();
70
+ }
71
+ async fetchWithRetry(packageName) {
72
+ const url = this.buildUrl(packageName);
73
+ let lastError = null;
74
+ for (let attempt = 0; attempt <= this.options.retry; attempt++) {
75
+ try {
76
+ const controller = new AbortController();
77
+ const timeoutId = setTimeout(() => controller.abort(), this.options.timeout);
78
+ const response = await fetch(url, {
79
+ signal: controller.signal,
80
+ headers: this.buildHeaders(),
81
+ });
82
+ clearTimeout(timeoutId);
83
+ if (!response.ok) {
84
+ if (response.status === 404) {
85
+ throw new Error(`Package not found: ${packageName}`);
86
+ }
87
+ throw new Error(`Registry returned ${response.status} for ${packageName}`);
88
+ }
89
+ const data = (await response.json());
90
+ return data;
91
+ }
92
+ catch (err) {
93
+ lastError = err;
94
+ if (attempt < this.options.retry) {
95
+ // Exponential backoff: 100ms, 200ms, 400ms...
96
+ await new Promise((r) => setTimeout(r, 100 * Math.pow(2, attempt)));
97
+ }
98
+ }
99
+ }
100
+ throw lastError ?? new Error(`Failed to fetch ${packageName}`);
101
+ }
102
+ buildUrl(packageName) {
103
+ const registry = this.options.registry.replace(/\/$/, '');
104
+ // Scoped packages need encoding: @scope/name -> @scope%2fname
105
+ const encoded = packageName.startsWith('@')
106
+ ? `@${encodeURIComponent(packageName.slice(1))}`
107
+ : encodeURIComponent(packageName);
108
+ return `${registry}/${encoded}`;
109
+ }
110
+ buildHeaders() {
111
+ const headers = {
112
+ Accept: 'application/json',
113
+ };
114
+ // Support auth token from npm config
115
+ const token = process.env.NPM_TOKEN;
116
+ if (token) {
117
+ headers['Authorization'] = `Bearer ${token}`;
118
+ }
119
+ return headers;
120
+ }
121
+ resolveCachePath() {
122
+ const cachePath = this.options.cacheFile.replace(/^~/, homedir());
123
+ return resolve(cachePath);
124
+ }
125
+ async loadDiskCache() {
126
+ if (this.diskCacheLoaded && this.diskCache)
127
+ return this.diskCache;
128
+ const cachePath = this.resolveCachePath();
129
+ try {
130
+ const raw = await readFile(cachePath, 'utf-8');
131
+ this.diskCache = JSON.parse(raw);
132
+ }
133
+ catch {
134
+ this.diskCache = {};
135
+ }
136
+ this.diskCacheLoaded = true;
137
+ return this.diskCache;
138
+ }
139
+ async getDiskCacheEntry(packageName) {
140
+ const cache = await this.loadDiskCache();
141
+ const entry = cache[packageName];
142
+ if (!entry)
143
+ return null;
144
+ const expirationMs = this.options.cacheExpiration * 60 * 1000;
145
+ if (Date.now() - entry.timestamp > expirationMs) {
146
+ delete cache[packageName];
147
+ return null;
148
+ }
149
+ return entry.data;
150
+ }
151
+ async setDiskCacheEntry(packageName, data) {
152
+ const cache = await this.loadDiskCache();
153
+ cache[packageName] = { data, timestamp: Date.now() };
154
+ const cachePath = this.resolveCachePath();
155
+ try {
156
+ await mkdir(dirname(cachePath), { recursive: true });
157
+ await writeFile(cachePath, JSON.stringify(cache), 'utf-8');
158
+ }
159
+ catch {
160
+ // Non-fatal: cache write failure shouldn't break the tool
161
+ }
162
+ }
163
+ }
164
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Release notes and SCM integration.
3
+ * Extracts repository URLs, fetches GitHub releases, builds compare URLs.
4
+ */
5
+ import type { NpmPackageMetadata, UpgradeResult } from './types.js';
6
+ interface GitHubRelease {
7
+ tag_name: string;
8
+ name: string;
9
+ body: string;
10
+ html_url: string;
11
+ published_at: string;
12
+ draft: boolean;
13
+ prerelease: boolean;
14
+ }
15
+ /** Parse a GitHub owner/repo from a repository URL or field */
16
+ export declare function parseGitHubRepo(repoField?: string | {
17
+ type?: string;
18
+ url?: string;
19
+ }): {
20
+ owner: string;
21
+ repo: string;
22
+ } | null;
23
+ /** Extract repository URL from package metadata */
24
+ export declare function getRepositoryUrl(metadata: NpmPackageMetadata): string | undefined;
25
+ /** Build a GitHub compare URL between two versions */
26
+ export declare function buildCompareUrl(owner: string, repo: string, fromVersion: string, toVersion: string): string;
27
+ /** Build a GitHub release URL for a version */
28
+ export declare function buildReleaseUrl(owner: string, repo: string, version: string): string;
29
+ /** Build a GitHub repository URL */
30
+ export declare function buildRepoUrl(owner: string, repo: string): string;
31
+ /** Fetch release info from GitHub API */
32
+ export declare function fetchGitHubRelease(owner: string, repo: string, version: string, token?: string): Promise<GitHubRelease | null>;
33
+ /** Resolve a GitHub token from env or gh CLI */
34
+ export declare function resolveGitHubToken(explicit?: string): Promise<string | undefined>;
35
+ /** Enrich upgrade results with release info */
36
+ export declare function enrichWithReleaseInfo(upgrades: UpgradeResult[], metadataMap: Map<string, NpmPackageMetadata>, token?: string): Promise<void>;
37
+ /** Check if the package owner changed between versions */
38
+ export declare function checkOwnerChanged(metadata: NpmPackageMetadata, fromVersion: string, toVersion: string): boolean;
39
+ export {};
40
+ //# sourceMappingURL=release-info.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-info.d.ts","sourceRoot":"","sources":["../src/release-info.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAe,aAAa,EAAE,MAAM,YAAY,CAAC;AAEjF,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,+DAA+D;AAC/D,wBAAgB,eAAe,CAC7B,SAAS,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA+BxC;AAED,mDAAmD;AACnD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,MAAM,GAAG,SAAS,CAajF;AAED,sDAAsD;AACtD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,CAER;AAED,+CAA+C;AAC/C,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,MAAM,CAER;AAED,oCAAoC;AACpC,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,yCAAyC;AACzC,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CA6B/B;AAED,gDAAgD;AAChD,wBAAsB,kBAAkB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAuBvF;AAED,+CAA+C;AAC/C,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,aAAa,EAAE,EACzB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,EAC5C,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAuCf;AAED,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,kBAAkB,EAC5B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAUT"}
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Release notes and SCM integration.
3
+ * Extracts repository URLs, fetches GitHub releases, builds compare URLs.
4
+ */
5
+ /** Parse a GitHub owner/repo from a repository URL or field */
6
+ export function parseGitHubRepo(repoField) {
7
+ let url;
8
+ if (typeof repoField === 'string') {
9
+ url = repoField;
10
+ }
11
+ else if (repoField?.url) {
12
+ url = repoField.url;
13
+ }
14
+ if (!url)
15
+ return null;
16
+ // Handle various URL formats:
17
+ // https://github.com/owner/repo
18
+ // https://github.com/owner/repo.git
19
+ // git+https://github.com/owner/repo.git
20
+ // git://github.com/owner/repo.git
21
+ // git@github.com:owner/repo.git
22
+ // github:owner/repo
23
+ const patterns = [
24
+ /github\.com[/:]([\w.-]+)\/([\w.-]+?)(?:\.git)?$/,
25
+ /^github:([\w.-]+)\/([\w.-]+)$/,
26
+ ];
27
+ for (const pattern of patterns) {
28
+ const match = url.match(pattern);
29
+ if (match) {
30
+ return { owner: match[1], repo: match[2] };
31
+ }
32
+ }
33
+ return null;
34
+ }
35
+ /** Extract repository URL from package metadata */
36
+ export function getRepositoryUrl(metadata) {
37
+ const repo = metadata.repository;
38
+ if (typeof repo === 'string') {
39
+ const gh = parseGitHubRepo(repo);
40
+ if (gh)
41
+ return `https://github.com/${gh.owner}/${gh.repo}`;
42
+ return repo;
43
+ }
44
+ if (repo?.url) {
45
+ const gh = parseGitHubRepo(repo);
46
+ if (gh)
47
+ return `https://github.com/${gh.owner}/${gh.repo}`;
48
+ return repo.url.replace(/^git\+/, '').replace(/\.git$/, '');
49
+ }
50
+ return undefined;
51
+ }
52
+ /** Build a GitHub compare URL between two versions */
53
+ export function buildCompareUrl(owner, repo, fromVersion, toVersion) {
54
+ return `https://github.com/${owner}/${repo}/compare/v${fromVersion}...v${toVersion}`;
55
+ }
56
+ /** Build a GitHub release URL for a version */
57
+ export function buildReleaseUrl(owner, repo, version) {
58
+ return `https://github.com/${owner}/${repo}/releases/tag/v${version}`;
59
+ }
60
+ /** Build a GitHub repository URL */
61
+ export function buildRepoUrl(owner, repo) {
62
+ return `https://github.com/${owner}/${repo}`;
63
+ }
64
+ /** Fetch release info from GitHub API */
65
+ export async function fetchGitHubRelease(owner, repo, version, token) {
66
+ // Try common tag formats
67
+ const tagCandidates = [
68
+ `v${version}`,
69
+ version,
70
+ ];
71
+ const headers = {
72
+ Accept: 'application/vnd.github+json',
73
+ 'X-GitHub-Api-Version': '2022-11-28',
74
+ };
75
+ if (token) {
76
+ headers['Authorization'] = `Bearer ${token}`;
77
+ }
78
+ for (const tag of tagCandidates) {
79
+ try {
80
+ const url = `https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/releases/tags/${encodeURIComponent(tag)}`;
81
+ const response = await fetch(url, { headers });
82
+ if (response.ok) {
83
+ return (await response.json());
84
+ }
85
+ }
86
+ catch {
87
+ // Try next format
88
+ }
89
+ }
90
+ return null;
91
+ }
92
+ /** Resolve a GitHub token from env or gh CLI */
93
+ export async function resolveGitHubToken(explicit) {
94
+ // Explicit token takes priority
95
+ if (explicit)
96
+ return explicit;
97
+ // Environment variable
98
+ if (process.env.GITHUB_TOKEN)
99
+ return process.env.GITHUB_TOKEN;
100
+ if (process.env.GH_TOKEN)
101
+ return process.env.GH_TOKEN;
102
+ // Try gh CLI
103
+ try {
104
+ const { execFile } = await import('node:child_process');
105
+ const { promisify } = await import('node:util');
106
+ const execFileP = promisify(execFile);
107
+ const { stdout } = await execFileP('gh', ['auth', 'token'], {
108
+ timeout: 5000,
109
+ });
110
+ const token = stdout.trim();
111
+ if (token)
112
+ return token;
113
+ }
114
+ catch {
115
+ // gh not installed or not authenticated
116
+ }
117
+ return undefined;
118
+ }
119
+ /** Enrich upgrade results with release info */
120
+ export async function enrichWithReleaseInfo(upgrades, metadataMap, token) {
121
+ const promises = upgrades.map(async (upgrade) => {
122
+ const metadata = metadataMap.get(upgrade.name);
123
+ if (!metadata)
124
+ return;
125
+ const repoUrl = getRepositoryUrl(metadata);
126
+ upgrade.repositoryUrl = repoUrl;
127
+ upgrade.homepage = metadata.homepage;
128
+ const gh = parseGitHubRepo(metadata.repository);
129
+ if (!gh)
130
+ return;
131
+ upgrade.releaseInfo = {
132
+ tagName: `v${upgrade.targetVersion}`,
133
+ repoUrl: buildRepoUrl(gh.owner, gh.repo),
134
+ compareUrl: buildCompareUrl(gh.owner, gh.repo, upgrade.currentVersion, upgrade.targetVersion),
135
+ releaseUrl: buildReleaseUrl(gh.owner, gh.repo, upgrade.targetVersion),
136
+ };
137
+ // Try to fetch actual release data (for body text)
138
+ try {
139
+ const release = await fetchGitHubRelease(gh.owner, gh.repo, upgrade.targetVersion, token);
140
+ if (release) {
141
+ upgrade.releaseInfo.releaseName = release.name;
142
+ upgrade.releaseInfo.body = release.body;
143
+ upgrade.releaseInfo.publishedAt = release.published_at;
144
+ upgrade.releaseInfo.releaseUrl = release.html_url;
145
+ }
146
+ }
147
+ catch {
148
+ // Non-fatal
149
+ }
150
+ });
151
+ await Promise.all(promises);
152
+ }
153
+ /** Check if the package owner changed between versions */
154
+ export function checkOwnerChanged(metadata, fromVersion, toVersion) {
155
+ const fromMeta = metadata.versions[fromVersion];
156
+ const toMeta = metadata.versions[toVersion];
157
+ if (!fromMeta || !toMeta)
158
+ return false;
159
+ const fromOwner = fromMeta._npmUser?.name ?? fromMeta.maintainers?.[0]?.name;
160
+ const toOwner = toMeta._npmUser?.name ?? toMeta.maintainers?.[0]?.name;
161
+ if (!fromOwner || !toOwner)
162
+ return false;
163
+ return fromOwner !== toOwner;
164
+ }
165
+ //# sourceMappingURL=release-info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-info.js","sourceRoot":"","sources":["../src/release-info.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * npm security advisory checker.
3
+ * Queries the npm bulk advisory endpoint to flag packages with known vulnerabilities.
4
+ */
5
+ import type { Advisory, RuckupOptions, UpgradeResult } from './types.js';
6
+ /** Check security advisories for a set of packages */
7
+ export declare function checkAdvisories(upgrades: UpgradeResult[], options: RuckupOptions): Promise<Map<string, Advisory[]>>;
8
+ /** Enrich upgrade results with advisory data */
9
+ export declare function enrichWithAdvisories(upgrades: UpgradeResult[], advisories: Map<string, Advisory[]>): void;
10
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkBzE,sDAAsD;AACtD,wBAAsB,eAAe,CACnC,QAAQ,EAAE,aAAa,EAAE,EACzB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,CA6DlC;AAED,gDAAgD;AAChD,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,aAAa,EAAE,EACzB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,GAClC,IAAI,CAON"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * npm security advisory checker.
3
+ * Queries the npm bulk advisory endpoint to flag packages with known vulnerabilities.
4
+ */
5
+ /** Check security advisories for a set of packages */
6
+ export async function checkAdvisories(upgrades, options) {
7
+ const results = new Map();
8
+ // Build bulk request: package name -> [current version, target version]
9
+ const requestBody = {};
10
+ for (const u of upgrades) {
11
+ const versions = [];
12
+ if (u.currentVersion)
13
+ versions.push(u.currentVersion);
14
+ if (u.targetVersion)
15
+ versions.push(u.targetVersion);
16
+ if (versions.length > 0) {
17
+ requestBody[u.name] = versions;
18
+ }
19
+ }
20
+ if (Object.keys(requestBody).length === 0)
21
+ return results;
22
+ try {
23
+ const registry = options.registry.replace(/\/$/, '');
24
+ const url = `${registry}/-/npm/v1/security/advisories/bulk`;
25
+ const controller = new AbortController();
26
+ const timeoutId = setTimeout(() => controller.abort(), options.timeout);
27
+ const response = await fetch(url, {
28
+ method: 'POST',
29
+ headers: {
30
+ 'Content-Type': 'application/json',
31
+ Accept: 'application/json',
32
+ },
33
+ body: JSON.stringify(requestBody),
34
+ signal: controller.signal,
35
+ });
36
+ clearTimeout(timeoutId);
37
+ if (!response.ok) {
38
+ // Advisory endpoint may not be available on custom registries
39
+ return results;
40
+ }
41
+ const data = (await response.json());
42
+ // Group advisories by package name
43
+ for (const advisory of Object.values(data)) {
44
+ const packageName = advisory.module_name;
45
+ if (!results.has(packageName)) {
46
+ results.set(packageName, []);
47
+ }
48
+ results.get(packageName).push({
49
+ id: advisory.id,
50
+ title: advisory.title,
51
+ url: advisory.url,
52
+ severity: advisory.severity,
53
+ vulnerableVersions: advisory.vulnerable_versions,
54
+ recommendation: advisory.recommendation,
55
+ });
56
+ }
57
+ }
58
+ catch {
59
+ // Non-fatal: advisory check failure shouldn't break the tool
60
+ }
61
+ return results;
62
+ }
63
+ /** Enrich upgrade results with advisory data */
64
+ export function enrichWithAdvisories(upgrades, advisories) {
65
+ for (const upgrade of upgrades) {
66
+ const pkgAdvisories = advisories.get(upgrade.name);
67
+ if (pkgAdvisories && pkgAdvisories.length > 0) {
68
+ upgrade.advisories = pkgAdvisories;
69
+ }
70
+ }
71
+ }
72
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"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"}