check-npm-lockfile 0.0.3 → 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.
@@ -1,6 +1,17 @@
1
1
  // src/parsers/yarn-lock.ts
2
2
  import lockfile from "@yarnpkg/lockfile";
3
3
  import { parse as parseYaml } from "yaml";
4
+ function extractRegistryNameFromResolved(resolved) {
5
+ if (!resolved || !resolved.startsWith("npm:")) {
6
+ return void 0;
7
+ }
8
+ const match = resolved.match(/^npm:(@?[^@]+)@/);
9
+ return match ? match[1] : void 0;
10
+ }
11
+ function extractRegistryNameFromKey(key) {
12
+ const npmMatch = key.match(/@npm:(@?[^@]+)@/);
13
+ return npmMatch ? npmMatch[1] : void 0;
14
+ }
4
15
  function detectYarnVersion(content) {
5
16
  if (content.includes("__metadata:")) {
6
17
  return "yarn-berry";
@@ -22,11 +33,13 @@ function parseYarnLockV1(content) {
22
33
  const uniqueKey = `${name}@${version}`;
23
34
  if (seen.has(uniqueKey)) continue;
24
35
  seen.add(uniqueKey);
36
+ const resolved = value.resolved;
25
37
  packages.push({
26
38
  name,
27
39
  version,
28
- resolved: value.resolved,
29
- integrity: value.integrity
40
+ resolved,
41
+ integrity: value.integrity,
42
+ registryName: extractRegistryNameFromKey(key) || extractRegistryNameFromResolved(resolved)
30
43
  });
31
44
  }
32
45
  return packages;
@@ -46,11 +59,13 @@ function parseYarnLockBerry(content) {
46
59
  const uniqueKey = `${name}@${version}`;
47
60
  if (seen.has(uniqueKey)) continue;
48
61
  seen.add(uniqueKey);
62
+ const resolved = value.resolution;
49
63
  packages.push({
50
64
  name,
51
65
  version,
52
- resolved: value.resolution,
53
- integrity: value.checksum
66
+ resolved,
67
+ integrity: value.checksum,
68
+ registryName: extractRegistryNameFromKey(descriptor) || extractRegistryNameFromResolved(resolved)
54
69
  });
55
70
  break;
56
71
  }
@@ -64,6 +79,13 @@ function parseYarnLock(content) {
64
79
  }
65
80
 
66
81
  // src/parsers/package-lock.ts
82
+ function extractRegistryName(resolved) {
83
+ if (!resolved || !resolved.startsWith("npm:")) {
84
+ return void 0;
85
+ }
86
+ const match = resolved.match(/^npm:(@?[^@]+)@/);
87
+ return match ? match[1] : void 0;
88
+ }
67
89
  function parsePackageLock(content) {
68
90
  const parsed = JSON.parse(content);
69
91
  const lockfileVersion = parsed.lockfileVersion || 1;
@@ -83,7 +105,8 @@ function parsePackageLockV2(data) {
83
105
  name: packageName,
84
106
  version: info.version,
85
107
  resolved: info.resolved,
86
- integrity: info.integrity
108
+ integrity: info.integrity,
109
+ registryName: extractRegistryName(info.resolved)
87
110
  });
88
111
  }
89
112
  return deduplicatePackages(packages);
@@ -96,7 +119,8 @@ function parsePackageLockV1(data) {
96
119
  name,
97
120
  version: info.version,
98
121
  resolved: info.resolved,
99
- integrity: info.integrity
122
+ integrity: info.integrity,
123
+ registryName: extractRegistryName(info.resolved)
100
124
  });
101
125
  if (info.dependencies) {
102
126
  traverse(info.dependencies);
@@ -221,7 +245,7 @@ async function analyzeLockfile(lockfilePath, options, onProgress) {
221
245
  let processed = 0;
222
246
  const checkPromises = filteredPackages.map(async (pkg) => {
223
247
  try {
224
- const timeInfo = await client.getPackageTime(pkg.name);
248
+ const timeInfo = await client.getPackageTime(pkg.registryName || pkg.name);
225
249
  const publishedAt = new Date(timeInfo[pkg.version]);
226
250
  if (isNaN(publishedAt.getTime())) {
227
251
  throw new Error(`Invalid publish date for version ${pkg.version}`);
@@ -235,6 +259,7 @@ async function analyzeLockfile(lockfilePath, options, onProgress) {
235
259
  recentPackages.push({
236
260
  name: pkg.name,
237
261
  version: pkg.version,
262
+ registryName: pkg.registryName,
238
263
  publishedAt,
239
264
  isNew,
240
265
  daysAgo,
@@ -341,8 +366,9 @@ function formatConsole(result) {
341
366
  for (const pkg of result.recentPackages) {
342
367
  const newBadge = pkg.isNew ? chalk.bgRed.white(" NEW ") + " " : " ";
343
368
  const daysLabel = pkg.daysAgo === 0 ? "today" : pkg.daysAgo === 1 ? "1 day ago" : `${pkg.daysAgo} days ago`;
369
+ const displayName = pkg.registryName ? `${pkg.name} ${chalk.gray("\u2192")} ${pkg.registryName}` : pkg.name;
344
370
  console.log(
345
- `${newBadge}${chalk.bold(pkg.name)}@${chalk.yellow(pkg.version)}`
371
+ `${newBadge}${chalk.bold(displayName)}@${chalk.yellow(pkg.version)}`
346
372
  );
347
373
  console.log(
348
374
  ` Published: ${chalk.gray(pkg.publishedAt.toISOString())} (${chalk.yellow(daysLabel)})`
@@ -395,4 +421,4 @@ export {
395
421
  formatJson,
396
422
  formatOutput
397
423
  };
398
- //# sourceMappingURL=chunk-3YXJPGA4.js.map
424
+ //# sourceMappingURL=chunk-WYSKMPXQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/parsers/yarn-lock.ts","../src/parsers/package-lock.ts","../src/registry/npm-client.ts","../src/analyzer/index.ts","../src/output/console.ts","../src/output/json.ts","../src/output/index.ts"],"sourcesContent":["import lockfile from \"@yarnpkg/lockfile\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { ParsedPackage } from \"../types/index.js\";\n\nfunction extractRegistryNameFromResolved(\n resolved: string | undefined\n): string | undefined {\n if (!resolved || !resolved.startsWith(\"npm:\")) {\n return undefined;\n }\n // npm:string-width@4.2.3 → string-width\n // npm:@scope/package@1.0.0 → @scope/package\n const match = resolved.match(/^npm:(@?[^@]+)@/);\n return match ? match[1] : undefined;\n}\n\nfunction extractRegistryNameFromKey(key: string): string | undefined {\n // \"string-width-cjs@npm:string-width@^4.2.0\" → string-width\n // \"alias@npm:@scope/package@^1.0.0\" → @scope/package\n const npmMatch = key.match(/@npm:(@?[^@]+)@/);\n return npmMatch ? npmMatch[1] : undefined;\n}\n\nexport function detectYarnVersion(content: string): \"yarn-v1\" | \"yarn-berry\" {\n if (content.includes(\"__metadata:\")) {\n return \"yarn-berry\";\n }\n return \"yarn-v1\";\n}\n\nexport function parseYarnLockV1(content: string): ParsedPackage[] {\n const result = lockfile.parse(content);\n\n if (result.type !== \"success\") {\n throw new Error(\"Failed to parse yarn.lock file\");\n }\n\n const packages: ParsedPackage[] = [];\n const seen = new Set<string>();\n\n for (const [key, value] of Object.entries(result.object)) {\n const match = key.match(/^(@?[^@]+)@/);\n if (!match) continue;\n\n const name = match[1];\n const version = (value as { version: string }).version;\n const uniqueKey = `${name}@${version}`;\n\n if (seen.has(uniqueKey)) continue;\n seen.add(uniqueKey);\n\n const resolved = (value as { resolved?: string }).resolved;\n packages.push({\n name,\n version,\n resolved,\n integrity: (value as { integrity?: string }).integrity,\n registryName: extractRegistryNameFromKey(key) || extractRegistryNameFromResolved(resolved),\n });\n }\n\n return packages;\n}\n\nexport function parseYarnLockBerry(content: string): ParsedPackage[] {\n const parsed = parseYaml(content) as Record<string, unknown>;\n const packages: ParsedPackage[] = [];\n const seen = new Set<string>();\n\n for (const [key, value] of Object.entries(parsed)) {\n if (key === \"__metadata\") continue;\n\n const descriptors = key.split(\", \");\n\n for (const descriptor of descriptors) {\n const match = descriptor.match(/^(@?[^@]+)@/);\n if (!match) continue;\n\n const name = match[1];\n const version = (value as { version: string }).version;\n const uniqueKey = `${name}@${version}`;\n\n if (seen.has(uniqueKey)) continue;\n seen.add(uniqueKey);\n\n const resolved = (value as { resolution?: string }).resolution;\n packages.push({\n name,\n version,\n resolved,\n integrity: (value as { checksum?: string }).checksum,\n registryName: extractRegistryNameFromKey(descriptor) || extractRegistryNameFromResolved(resolved),\n });\n\n break;\n }\n }\n\n return packages;\n}\n\nexport function parseYarnLock(content: string): {\n packages: ParsedPackage[];\n version: \"yarn-v1\" | \"yarn-berry\";\n} {\n const version = detectYarnVersion(content);\n const packages =\n version === \"yarn-v1\"\n ? parseYarnLockV1(content)\n : parseYarnLockBerry(content);\n return { packages, version };\n}\n","import type { ParsedPackage } from \"../types/index.js\";\n\nfunction extractRegistryName(\n resolved: string | undefined\n): string | undefined {\n if (!resolved || !resolved.startsWith(\"npm:\")) {\n return undefined;\n }\n // npm:string-width@4.2.3 → string-width\n // npm:@scope/package@1.0.0 → @scope/package\n const match = resolved.match(/^npm:(@?[^@]+)@/);\n return match ? match[1] : undefined;\n}\n\ninterface PackageLockV2 {\n lockfileVersion: number;\n packages: Record<\n string,\n {\n version: string;\n resolved?: string;\n integrity?: string;\n }\n >;\n}\n\ninterface PackageLockV1 {\n lockfileVersion: 1;\n dependencies: Record<\n string,\n {\n version: string;\n resolved?: string;\n integrity?: string;\n dependencies?: Record<string, unknown>;\n }\n >;\n}\n\nexport function parsePackageLock(content: string): ParsedPackage[] {\n const parsed = JSON.parse(content) as { lockfileVersion?: number };\n const lockfileVersion = parsed.lockfileVersion || 1;\n\n if (lockfileVersion >= 2) {\n return parsePackageLockV2(parsed as PackageLockV2);\n }\n\n return parsePackageLockV1(parsed as PackageLockV1);\n}\n\nfunction parsePackageLockV2(data: PackageLockV2): ParsedPackage[] {\n const packages: ParsedPackage[] = [];\n\n for (const [path, info] of Object.entries(data.packages || {})) {\n if (path === \"\") continue;\n\n const segments = path.split(\"node_modules/\");\n const packageName = segments[segments.length - 1];\n\n if (!packageName || !info.version) continue;\n\n packages.push({\n name: packageName,\n version: info.version,\n resolved: info.resolved,\n integrity: info.integrity,\n registryName: extractRegistryName(info.resolved),\n });\n }\n\n return deduplicatePackages(packages);\n}\n\nfunction parsePackageLockV1(data: PackageLockV1): ParsedPackage[] {\n const packages: ParsedPackage[] = [];\n\n function traverse(deps: Record<string, { version: string; resolved?: string; integrity?: string; dependencies?: Record<string, unknown> }>) {\n for (const [name, info] of Object.entries(deps)) {\n packages.push({\n name,\n version: info.version,\n resolved: info.resolved,\n integrity: info.integrity,\n registryName: extractRegistryName(info.resolved),\n });\n\n if (info.dependencies) {\n traverse(info.dependencies as typeof deps);\n }\n }\n }\n\n traverse(data.dependencies || {});\n return deduplicatePackages(packages);\n}\n\nfunction deduplicatePackages(packages: ParsedPackage[]): ParsedPackage[] {\n const seen = new Map<string, ParsedPackage>();\n\n for (const pkg of packages) {\n const key = `${pkg.name}@${pkg.version}`;\n if (!seen.has(key)) {\n seen.set(key, pkg);\n }\n }\n\n return Array.from(seen.values());\n}\n","import pLimit from \"p-limit\";\nimport type { PackageTimeInfo } from \"../types/index.js\";\n\nconst NPM_REGISTRY = \"https://registry.npmjs.org\";\n\nexport class NpmRegistryClient {\n private cache: Map<string, PackageTimeInfo> = new Map();\n private limiter: ReturnType<typeof pLimit>;\n private retryDelay = 1000;\n private maxRetries = 3;\n\n constructor(concurrency = 10) {\n this.limiter = pLimit(concurrency);\n }\n\n async getPackageTime(name: string): Promise<PackageTimeInfo> {\n const cached = this.cache.get(name);\n if (cached) return cached;\n\n return this.limiter(async () => {\n const cachedAfterWait = this.cache.get(name);\n if (cachedAfterWait) return cachedAfterWait;\n\n const data = await this.fetchWithRetry(name);\n this.cache.set(name, data);\n return data;\n });\n }\n\n private async fetchWithRetry(\n name: string,\n attempt = 1\n ): Promise<PackageTimeInfo> {\n const url = `${NPM_REGISTRY}/${encodeURIComponent(name).replace(\"%40\", \"@\")}`;\n\n try {\n const response = await fetch(url, {\n headers: {\n Accept: \"application/json\",\n },\n });\n\n if (response.status === 429) {\n if (attempt <= this.maxRetries) {\n const delay = this.retryDelay * Math.pow(2, attempt - 1);\n await this.sleep(delay);\n return this.fetchWithRetry(name, attempt + 1);\n }\n throw new Error(`Rate limited after ${this.maxRetries} retries`);\n }\n\n if (response.status === 404) {\n throw new Error(`Package not found: ${name}`);\n }\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const data = (await response.json()) as { time: PackageTimeInfo };\n return data.time;\n } catch (error) {\n if (attempt <= this.maxRetries && this.isRetryableError(error)) {\n const delay = this.retryDelay * Math.pow(2, attempt - 1);\n await this.sleep(delay);\n return this.fetchWithRetry(name, attempt + 1);\n }\n throw error;\n }\n }\n\n private isRetryableError(error: unknown): boolean {\n if (error instanceof Error) {\n return (\n error.message.includes(\"ECONNRESET\") ||\n error.message.includes(\"ETIMEDOUT\") ||\n error.message.includes(\"fetch failed\")\n );\n }\n return false;\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import { readFileSync, existsSync } from \"fs\";\nimport { resolve, basename } from \"path\";\nimport { parseYarnLock } from \"../parsers/yarn-lock.js\";\nimport { parsePackageLock } from \"../parsers/package-lock.js\";\nimport { NpmRegistryClient } from \"../registry/npm-client.js\";\nimport type {\n ParsedPackage,\n AnalysisResult,\n PackageCheckResult,\n PackageError,\n CLIOptions,\n LockfileType,\n PackageTimeInfo,\n} from \"../types/index.js\";\n\nexport function parseMinimumReleaseAge(value: string): number {\n const match = value.match(/^(\\d+)\\s*(days?|hours?|minutes?)?$/i);\n if (!match) {\n throw new Error(\n `Invalid minimumReleaseAge format: \"${value}\". Use format like \"3 days\", \"7 days\", or \"24 hours\"`\n );\n }\n\n const num = parseInt(match[1], 10);\n const unit = (match[2] || \"days\").toLowerCase();\n\n if (unit.startsWith(\"day\")) {\n return num;\n } else if (unit.startsWith(\"hour\")) {\n return num / 24;\n } else if (unit.startsWith(\"minute\")) {\n return num / (24 * 60);\n }\n\n return num;\n}\n\nexport async function analyzeLockfile(\n lockfilePath: string | undefined,\n options: CLIOptions,\n onProgress?: (current: number, total: number) => void\n): Promise<AnalysisResult> {\n const resolvedPath = resolveLockfilePath(lockfilePath);\n const content = readFileSync(resolvedPath, \"utf-8\");\n\n const { packages, lockfileType } = parseLockfile(resolvedPath, content);\n\n const filteredPackages = packages.filter(\n (pkg) => !options.exclude.includes(pkg.name)\n );\n\n const client = new NpmRegistryClient(options.concurrency);\n const thresholdDays = parseMinimumReleaseAge(options.minimumReleaseAge);\n const thresholdDate = new Date();\n thresholdDate.setDate(thresholdDate.getDate() - thresholdDays);\n\n const recentPackages: PackageCheckResult[] = [];\n const errors: PackageError[] = [];\n\n const total = filteredPackages.length;\n let processed = 0;\n\n const checkPromises = filteredPackages.map(async (pkg) => {\n try {\n const timeInfo = await client.getPackageTime(pkg.registryName || pkg.name);\n const publishedAt = new Date(timeInfo[pkg.version]);\n\n if (isNaN(publishedAt.getTime())) {\n throw new Error(`Invalid publish date for version ${pkg.version}`);\n }\n\n const daysAgo = Math.floor(\n (Date.now() - publishedAt.getTime()) / (1000 * 60 * 60 * 24)\n );\n\n const isWithinThreshold = publishedAt >= thresholdDate;\n const isNew = isFirstVersion(timeInfo, pkg.version);\n\n if (isWithinThreshold) {\n recentPackages.push({\n name: pkg.name,\n version: pkg.version,\n registryName: pkg.registryName,\n publishedAt,\n isNew,\n daysAgo,\n isWithinThreshold,\n });\n }\n } catch (error) {\n errors.push({\n name: pkg.name,\n version: pkg.version,\n error: error instanceof Error ? error.message : String(error),\n });\n } finally {\n processed++;\n onProgress?.(processed, total);\n }\n });\n\n await Promise.all(checkPromises);\n\n recentPackages.sort(\n (a, b) => b.publishedAt.getTime() - a.publishedAt.getTime()\n );\n\n return {\n lockfileType,\n lockfilePath: resolvedPath,\n totalPackages: filteredPackages.length,\n checkedPackages: filteredPackages.length - errors.length,\n recentPackages,\n errors,\n analysisDate: new Date(),\n thresholdDays,\n };\n}\n\nfunction resolveLockfilePath(path?: string): string {\n if (path) {\n const resolved = resolve(path);\n if (!existsSync(resolved)) {\n throw new Error(`Lockfile not found: ${resolved}`);\n }\n return resolved;\n }\n\n const candidates = [\"yarn.lock\", \"package-lock.json\"];\n\n for (const candidate of candidates) {\n const resolved = resolve(candidate);\n if (existsSync(resolved)) {\n return resolved;\n }\n }\n\n throw new Error(\n \"No lockfile found. Please specify a path or run in a directory with yarn.lock or package-lock.json\"\n );\n}\n\nfunction parseLockfile(\n path: string,\n content: string\n): { packages: ParsedPackage[]; lockfileType: LockfileType } {\n const filename = basename(path);\n\n if (filename === \"yarn.lock\") {\n const { packages, version } = parseYarnLock(content);\n return { packages, lockfileType: version };\n }\n\n if (filename === \"package-lock.json\") {\n return {\n packages: parsePackageLock(content),\n lockfileType: \"npm\",\n };\n }\n\n throw new Error(`Unsupported lockfile: ${filename}`);\n}\n\nfunction isFirstVersion(\n timeInfo: PackageTimeInfo,\n version: string\n): boolean {\n const versions = Object.keys(timeInfo).filter(\n (k) => k !== \"created\" && k !== \"modified\"\n );\n\n if (versions.length === 0) return true;\n\n let earliestVersion = versions[0];\n let earliestDate = new Date(timeInfo[versions[0]]);\n\n for (const v of versions) {\n const date = new Date(timeInfo[v]);\n if (date < earliestDate) {\n earliestDate = date;\n earliestVersion = v;\n }\n }\n\n return version === earliestVersion;\n}\n","import chalk from \"chalk\";\nimport type { AnalysisResult } from \"../types/index.js\";\n\nexport function formatConsole(result: AnalysisResult): void {\n console.log();\n console.log(chalk.bold(\"Lockfile Analysis Report\"));\n console.log(chalk.gray(\"-\".repeat(50)));\n console.log(`File: ${chalk.cyan(result.lockfilePath)}`);\n console.log(`Type: ${chalk.cyan(result.lockfileType)}`);\n console.log(`Threshold: ${chalk.yellow(result.thresholdDays)} days`);\n console.log(`Total packages: ${result.totalPackages}`);\n console.log(`Checked: ${result.checkedPackages}`);\n console.log();\n\n if (result.recentPackages.length === 0) {\n console.log(chalk.green(\"No recently published packages found.\"));\n } else {\n console.log(\n chalk.red.bold(\n `Found ${result.recentPackages.length} package(s) published within ${result.thresholdDays} days:`\n )\n );\n console.log();\n\n for (const pkg of result.recentPackages) {\n const newBadge = pkg.isNew ? chalk.bgRed.white(\" NEW \") + \" \" : \" \";\n const daysLabel =\n pkg.daysAgo === 0\n ? \"today\"\n : pkg.daysAgo === 1\n ? \"1 day ago\"\n : `${pkg.daysAgo} days ago`;\n\n const displayName = pkg.registryName\n ? `${pkg.name} ${chalk.gray(\"→\")} ${pkg.registryName}`\n : pkg.name;\n console.log(\n `${newBadge}${chalk.bold(displayName)}@${chalk.yellow(pkg.version)}`\n );\n console.log(\n ` Published: ${chalk.gray(pkg.publishedAt.toISOString())} (${chalk.yellow(daysLabel)})`\n );\n }\n }\n\n if (result.errors.length > 0) {\n console.log();\n console.log(\n chalk.yellow(\n `Warnings: ${result.errors.length} package(s) could not be checked`\n )\n );\n\n for (const err of result.errors) {\n console.log(chalk.gray(` - ${err.name}@${err.version}: ${err.error}`));\n }\n }\n\n console.log();\n}\n","import type { AnalysisResult } from \"../types/index.js\";\n\nexport function formatJson(result: AnalysisResult): void {\n const output = {\n ...result,\n recentPackages: result.recentPackages.map((pkg) => ({\n ...pkg,\n publishedAt: pkg.publishedAt.toISOString(),\n })),\n analysisDate: result.analysisDate.toISOString(),\n };\n\n console.log(JSON.stringify(output, null, 2));\n}\n","import type { AnalysisResult } from \"../types/index.js\";\nimport { formatConsole } from \"./console.js\";\nimport { formatJson } from \"./json.js\";\n\nexport function formatOutput(\n result: AnalysisResult,\n format: \"console\" | \"json\"\n): void {\n if (format === \"json\") {\n formatJson(result);\n } else {\n formatConsole(result);\n }\n}\n\nexport { formatConsole } from \"./console.js\";\nexport { formatJson } from \"./json.js\";\n"],"mappings":";AAAA,OAAO,cAAc;AACrB,SAAS,SAAS,iBAAiB;AAGnC,SAAS,gCACP,UACoB;AACpB,MAAI,CAAC,YAAY,CAAC,SAAS,WAAW,MAAM,GAAG;AAC7C,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,SAAS,MAAM,iBAAiB;AAC9C,SAAO,QAAQ,MAAM,CAAC,IAAI;AAC5B;AAEA,SAAS,2BAA2B,KAAiC;AAGnE,QAAM,WAAW,IAAI,MAAM,iBAAiB;AAC5C,SAAO,WAAW,SAAS,CAAC,IAAI;AAClC;AAEO,SAAS,kBAAkB,SAA2C;AAC3E,MAAI,QAAQ,SAAS,aAAa,GAAG;AACnC,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,gBAAgB,SAAkC;AAChE,QAAM,SAAS,SAAS,MAAM,OAAO;AAErC,MAAI,OAAO,SAAS,WAAW;AAC7B,UAAM,IAAI,MAAM,gCAAgC;AAAA,EAClD;AAEA,QAAM,WAA4B,CAAC;AACnC,QAAM,OAAO,oBAAI,IAAY;AAE7B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AACxD,UAAM,QAAQ,IAAI,MAAM,aAAa;AACrC,QAAI,CAAC,MAAO;AAEZ,UAAM,OAAO,MAAM,CAAC;AACpB,UAAM,UAAW,MAA8B;AAC/C,UAAM,YAAY,GAAG,IAAI,IAAI,OAAO;AAEpC,QAAI,KAAK,IAAI,SAAS,EAAG;AACzB,SAAK,IAAI,SAAS;AAElB,UAAM,WAAY,MAAgC;AAClD,aAAS,KAAK;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAY,MAAiC;AAAA,MAC7C,cAAc,2BAA2B,GAAG,KAAK,gCAAgC,QAAQ;AAAA,IAC3F,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEO,SAAS,mBAAmB,SAAkC;AACnE,QAAM,SAAS,UAAU,OAAO;AAChC,QAAM,WAA4B,CAAC;AACnC,QAAM,OAAO,oBAAI,IAAY;AAE7B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,QAAI,QAAQ,aAAc;AAE1B,UAAM,cAAc,IAAI,MAAM,IAAI;AAElC,eAAW,cAAc,aAAa;AACpC,YAAM,QAAQ,WAAW,MAAM,aAAa;AAC5C,UAAI,CAAC,MAAO;AAEZ,YAAM,OAAO,MAAM,CAAC;AACpB,YAAM,UAAW,MAA8B;AAC/C,YAAM,YAAY,GAAG,IAAI,IAAI,OAAO;AAEpC,UAAI,KAAK,IAAI,SAAS,EAAG;AACzB,WAAK,IAAI,SAAS;AAElB,YAAM,WAAY,MAAkC;AACpD,eAAS,KAAK;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA,WAAY,MAAgC;AAAA,QAC5C,cAAc,2BAA2B,UAAU,KAAK,gCAAgC,QAAQ;AAAA,MAClG,CAAC;AAED;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,cAAc,SAG5B;AACA,QAAM,UAAU,kBAAkB,OAAO;AACzC,QAAM,WACJ,YAAY,YACR,gBAAgB,OAAO,IACvB,mBAAmB,OAAO;AAChC,SAAO,EAAE,UAAU,QAAQ;AAC7B;;;AC7GA,SAAS,oBACP,UACoB;AACpB,MAAI,CAAC,YAAY,CAAC,SAAS,WAAW,MAAM,GAAG;AAC7C,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,SAAS,MAAM,iBAAiB;AAC9C,SAAO,QAAQ,MAAM,CAAC,IAAI;AAC5B;AA2BO,SAAS,iBAAiB,SAAkC;AACjE,QAAM,SAAS,KAAK,MAAM,OAAO;AACjC,QAAM,kBAAkB,OAAO,mBAAmB;AAElD,MAAI,mBAAmB,GAAG;AACxB,WAAO,mBAAmB,MAAuB;AAAA,EACnD;AAEA,SAAO,mBAAmB,MAAuB;AACnD;AAEA,SAAS,mBAAmB,MAAsC;AAChE,QAAM,WAA4B,CAAC;AAEnC,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,KAAK,YAAY,CAAC,CAAC,GAAG;AAC9D,QAAI,SAAS,GAAI;AAEjB,UAAM,WAAW,KAAK,MAAM,eAAe;AAC3C,UAAM,cAAc,SAAS,SAAS,SAAS,CAAC;AAEhD,QAAI,CAAC,eAAe,CAAC,KAAK,QAAS;AAEnC,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,SAAS,KAAK;AAAA,MACd,UAAU,KAAK;AAAA,MACf,WAAW,KAAK;AAAA,MAChB,cAAc,oBAAoB,KAAK,QAAQ;AAAA,IACjD,CAAC;AAAA,EACH;AAEA,SAAO,oBAAoB,QAAQ;AACrC;AAEA,SAAS,mBAAmB,MAAsC;AAChE,QAAM,WAA4B,CAAC;AAEnC,WAAS,SAAS,MAA0H;AAC1I,eAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,IAAI,GAAG;AAC/C,eAAS,KAAK;AAAA,QACZ;AAAA,QACA,SAAS,KAAK;AAAA,QACd,UAAU,KAAK;AAAA,QACf,WAAW,KAAK;AAAA,QAChB,cAAc,oBAAoB,KAAK,QAAQ;AAAA,MACjD,CAAC;AAED,UAAI,KAAK,cAAc;AACrB,iBAAS,KAAK,YAA2B;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAEA,WAAS,KAAK,gBAAgB,CAAC,CAAC;AAChC,SAAO,oBAAoB,QAAQ;AACrC;AAEA,SAAS,oBAAoB,UAA4C;AACvE,QAAM,OAAO,oBAAI,IAA2B;AAE5C,aAAW,OAAO,UAAU;AAC1B,UAAM,MAAM,GAAG,IAAI,IAAI,IAAI,IAAI,OAAO;AACtC,QAAI,CAAC,KAAK,IAAI,GAAG,GAAG;AAClB,WAAK,IAAI,KAAK,GAAG;AAAA,IACnB;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,KAAK,OAAO,CAAC;AACjC;;;AC3GA,OAAO,YAAY;AAGnB,IAAM,eAAe;AAEd,IAAM,oBAAN,MAAwB;AAAA,EACrB,QAAsC,oBAAI,IAAI;AAAA,EAC9C;AAAA,EACA,aAAa;AAAA,EACb,aAAa;AAAA,EAErB,YAAY,cAAc,IAAI;AAC5B,SAAK,UAAU,OAAO,WAAW;AAAA,EACnC;AAAA,EAEA,MAAM,eAAe,MAAwC;AAC3D,UAAM,SAAS,KAAK,MAAM,IAAI,IAAI;AAClC,QAAI,OAAQ,QAAO;AAEnB,WAAO,KAAK,QAAQ,YAAY;AAC9B,YAAM,kBAAkB,KAAK,MAAM,IAAI,IAAI;AAC3C,UAAI,gBAAiB,QAAO;AAE5B,YAAM,OAAO,MAAM,KAAK,eAAe,IAAI;AAC3C,WAAK,MAAM,IAAI,MAAM,IAAI;AACzB,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,eACZ,MACA,UAAU,GACgB;AAC1B,UAAM,MAAM,GAAG,YAAY,IAAI,mBAAmB,IAAI,EAAE,QAAQ,OAAO,GAAG,CAAC;AAE3E,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,SAAS;AAAA,UACP,QAAQ;AAAA,QACV;AAAA,MACF,CAAC;AAED,UAAI,SAAS,WAAW,KAAK;AAC3B,YAAI,WAAW,KAAK,YAAY;AAC9B,gBAAM,QAAQ,KAAK,aAAa,KAAK,IAAI,GAAG,UAAU,CAAC;AACvD,gBAAM,KAAK,MAAM,KAAK;AACtB,iBAAO,KAAK,eAAe,MAAM,UAAU,CAAC;AAAA,QAC9C;AACA,cAAM,IAAI,MAAM,sBAAsB,KAAK,UAAU,UAAU;AAAA,MACjE;AAEA,UAAI,SAAS,WAAW,KAAK;AAC3B,cAAM,IAAI,MAAM,sBAAsB,IAAI,EAAE;AAAA,MAC9C;AAEA,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,MACnE;AAEA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,aAAO,KAAK;AAAA,IACd,SAAS,OAAO;AACd,UAAI,WAAW,KAAK,cAAc,KAAK,iBAAiB,KAAK,GAAG;AAC9D,cAAM,QAAQ,KAAK,aAAa,KAAK,IAAI,GAAG,UAAU,CAAC;AACvD,cAAM,KAAK,MAAM,KAAK;AACtB,eAAO,KAAK,eAAe,MAAM,UAAU,CAAC;AAAA,MAC9C;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEQ,iBAAiB,OAAyB;AAChD,QAAI,iBAAiB,OAAO;AAC1B,aACE,MAAM,QAAQ,SAAS,YAAY,KACnC,MAAM,QAAQ,SAAS,WAAW,KAClC,MAAM,QAAQ,SAAS,cAAc;AAAA,IAEzC;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,MAAM,IAA2B;AACvC,WAAO,IAAI,QAAQ,CAACA,aAAY,WAAWA,UAAS,EAAE,CAAC;AAAA,EACzD;AACF;;;ACrFA,SAAS,cAAc,kBAAkB;AACzC,SAAS,SAAS,gBAAgB;AAc3B,SAAS,uBAAuB,OAAuB;AAC5D,QAAM,QAAQ,MAAM,MAAM,qCAAqC;AAC/D,MAAI,CAAC,OAAO;AACV,UAAM,IAAI;AAAA,MACR,sCAAsC,KAAK;AAAA,IAC7C;AAAA,EACF;AAEA,QAAM,MAAM,SAAS,MAAM,CAAC,GAAG,EAAE;AACjC,QAAM,QAAQ,MAAM,CAAC,KAAK,QAAQ,YAAY;AAE9C,MAAI,KAAK,WAAW,KAAK,GAAG;AAC1B,WAAO;AAAA,EACT,WAAW,KAAK,WAAW,MAAM,GAAG;AAClC,WAAO,MAAM;AAAA,EACf,WAAW,KAAK,WAAW,QAAQ,GAAG;AACpC,WAAO,OAAO,KAAK;AAAA,EACrB;AAEA,SAAO;AACT;AAEA,eAAsB,gBACpB,cACA,SACA,YACyB;AACzB,QAAM,eAAe,oBAAoB,YAAY;AACrD,QAAM,UAAU,aAAa,cAAc,OAAO;AAElD,QAAM,EAAE,UAAU,aAAa,IAAI,cAAc,cAAc,OAAO;AAEtE,QAAM,mBAAmB,SAAS;AAAA,IAChC,CAAC,QAAQ,CAAC,QAAQ,QAAQ,SAAS,IAAI,IAAI;AAAA,EAC7C;AAEA,QAAM,SAAS,IAAI,kBAAkB,QAAQ,WAAW;AACxD,QAAM,gBAAgB,uBAAuB,QAAQ,iBAAiB;AACtE,QAAM,gBAAgB,oBAAI,KAAK;AAC/B,gBAAc,QAAQ,cAAc,QAAQ,IAAI,aAAa;AAE7D,QAAM,iBAAuC,CAAC;AAC9C,QAAM,SAAyB,CAAC;AAEhC,QAAM,QAAQ,iBAAiB;AAC/B,MAAI,YAAY;AAEhB,QAAM,gBAAgB,iBAAiB,IAAI,OAAO,QAAQ;AACxD,QAAI;AACF,YAAM,WAAW,MAAM,OAAO,eAAe,IAAI,gBAAgB,IAAI,IAAI;AACzE,YAAM,cAAc,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC;AAElD,UAAI,MAAM,YAAY,QAAQ,CAAC,GAAG;AAChC,cAAM,IAAI,MAAM,oCAAoC,IAAI,OAAO,EAAE;AAAA,MACnE;AAEA,YAAM,UAAU,KAAK;AAAA,SAClB,KAAK,IAAI,IAAI,YAAY,QAAQ,MAAM,MAAO,KAAK,KAAK;AAAA,MAC3D;AAEA,YAAM,oBAAoB,eAAe;AACzC,YAAM,QAAQ,eAAe,UAAU,IAAI,OAAO;AAElD,UAAI,mBAAmB;AACrB,uBAAe,KAAK;AAAA,UAClB,MAAM,IAAI;AAAA,UACV,SAAS,IAAI;AAAA,UACb,cAAc,IAAI;AAAA,UAClB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,SAAS,OAAO;AACd,aAAO,KAAK;AAAA,QACV,MAAM,IAAI;AAAA,QACV,SAAS,IAAI;AAAA,QACb,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MAC9D,CAAC;AAAA,IACH,UAAE;AACA;AACA,mBAAa,WAAW,KAAK;AAAA,IAC/B;AAAA,EACF,CAAC;AAED,QAAM,QAAQ,IAAI,aAAa;AAE/B,iBAAe;AAAA,IACb,CAAC,GAAG,MAAM,EAAE,YAAY,QAAQ,IAAI,EAAE,YAAY,QAAQ;AAAA,EAC5D;AAEA,SAAO;AAAA,IACL;AAAA,IACA,cAAc;AAAA,IACd,eAAe,iBAAiB;AAAA,IAChC,iBAAiB,iBAAiB,SAAS,OAAO;AAAA,IAClD;AAAA,IACA;AAAA,IACA,cAAc,oBAAI,KAAK;AAAA,IACvB;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,MAAuB;AAClD,MAAI,MAAM;AACR,UAAM,WAAW,QAAQ,IAAI;AAC7B,QAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,YAAM,IAAI,MAAM,uBAAuB,QAAQ,EAAE;AAAA,IACnD;AACA,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,CAAC,aAAa,mBAAmB;AAEpD,aAAW,aAAa,YAAY;AAClC,UAAM,WAAW,QAAQ,SAAS;AAClC,QAAI,WAAW,QAAQ,GAAG;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,IAAI;AAAA,IACR;AAAA,EACF;AACF;AAEA,SAAS,cACP,MACA,SAC2D;AAC3D,QAAM,WAAW,SAAS,IAAI;AAE9B,MAAI,aAAa,aAAa;AAC5B,UAAM,EAAE,UAAU,QAAQ,IAAI,cAAc,OAAO;AACnD,WAAO,EAAE,UAAU,cAAc,QAAQ;AAAA,EAC3C;AAEA,MAAI,aAAa,qBAAqB;AACpC,WAAO;AAAA,MACL,UAAU,iBAAiB,OAAO;AAAA,MAClC,cAAc;AAAA,IAChB;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,yBAAyB,QAAQ,EAAE;AACrD;AAEA,SAAS,eACP,UACA,SACS;AACT,QAAM,WAAW,OAAO,KAAK,QAAQ,EAAE;AAAA,IACrC,CAAC,MAAM,MAAM,aAAa,MAAM;AAAA,EAClC;AAEA,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,MAAI,kBAAkB,SAAS,CAAC;AAChC,MAAI,eAAe,IAAI,KAAK,SAAS,SAAS,CAAC,CAAC,CAAC;AAEjD,aAAW,KAAK,UAAU;AACxB,UAAM,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC;AACjC,QAAI,OAAO,cAAc;AACvB,qBAAe;AACf,wBAAkB;AAAA,IACpB;AAAA,EACF;AAEA,SAAO,YAAY;AACrB;;;ACzLA,OAAO,WAAW;AAGX,SAAS,cAAc,QAA8B;AAC1D,UAAQ,IAAI;AACZ,UAAQ,IAAI,MAAM,KAAK,0BAA0B,CAAC;AAClD,UAAQ,IAAI,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC;AACtC,UAAQ,IAAI,SAAS,MAAM,KAAK,OAAO,YAAY,CAAC,EAAE;AACtD,UAAQ,IAAI,SAAS,MAAM,KAAK,OAAO,YAAY,CAAC,EAAE;AACtD,UAAQ,IAAI,cAAc,MAAM,OAAO,OAAO,aAAa,CAAC,OAAO;AACnE,UAAQ,IAAI,mBAAmB,OAAO,aAAa,EAAE;AACrD,UAAQ,IAAI,YAAY,OAAO,eAAe,EAAE;AAChD,UAAQ,IAAI;AAEZ,MAAI,OAAO,eAAe,WAAW,GAAG;AACtC,YAAQ,IAAI,MAAM,MAAM,uCAAuC,CAAC;AAAA,EAClE,OAAO;AACL,YAAQ;AAAA,MACN,MAAM,IAAI;AAAA,QACR,SAAS,OAAO,eAAe,MAAM,gCAAgC,OAAO,aAAa;AAAA,MAC3F;AAAA,IACF;AACA,YAAQ,IAAI;AAEZ,eAAW,OAAO,OAAO,gBAAgB;AACvC,YAAM,WAAW,IAAI,QAAQ,MAAM,MAAM,MAAM,OAAO,IAAI,MAAM;AAChE,YAAM,YACJ,IAAI,YAAY,IACZ,UACA,IAAI,YAAY,IACd,cACA,GAAG,IAAI,OAAO;AAEtB,YAAM,cAAc,IAAI,eACpB,GAAG,IAAI,IAAI,IAAI,MAAM,KAAK,QAAG,CAAC,IAAI,IAAI,YAAY,KAClD,IAAI;AACR,cAAQ;AAAA,QACN,GAAG,QAAQ,GAAG,MAAM,KAAK,WAAW,CAAC,IAAI,MAAM,OAAO,IAAI,OAAO,CAAC;AAAA,MACpE;AACA,cAAQ;AAAA,QACN,kBAAkB,MAAM,KAAK,IAAI,YAAY,YAAY,CAAC,CAAC,KAAK,MAAM,OAAO,SAAS,CAAC;AAAA,MACzF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,OAAO,SAAS,GAAG;AAC5B,YAAQ,IAAI;AACZ,YAAQ;AAAA,MACN,MAAM;AAAA,QACJ,aAAa,OAAO,OAAO,MAAM;AAAA,MACnC;AAAA,IACF;AAEA,eAAW,OAAO,OAAO,QAAQ;AAC/B,cAAQ,IAAI,MAAM,KAAK,OAAO,IAAI,IAAI,IAAI,IAAI,OAAO,KAAK,IAAI,KAAK,EAAE,CAAC;AAAA,IACxE;AAAA,EACF;AAEA,UAAQ,IAAI;AACd;;;ACzDO,SAAS,WAAW,QAA8B;AACvD,QAAM,SAAS;AAAA,IACb,GAAG;AAAA,IACH,gBAAgB,OAAO,eAAe,IAAI,CAAC,SAAS;AAAA,MAClD,GAAG;AAAA,MACH,aAAa,IAAI,YAAY,YAAY;AAAA,IAC3C,EAAE;AAAA,IACF,cAAc,OAAO,aAAa,YAAY;AAAA,EAChD;AAEA,UAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC7C;;;ACTO,SAAS,aACd,QACA,QACM;AACN,MAAI,WAAW,QAAQ;AACrB,eAAW,MAAM;AAAA,EACnB,OAAO;AACL,kBAAc,MAAM;AAAA,EACtB;AACF;","names":["resolve"]}
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  analyzeLockfile,
4
4
  formatOutput
5
- } from "./chunk-3YXJPGA4.js";
5
+ } from "./chunk-WYSKMPXQ.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import { Command } from "commander";
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ interface ParsedPackage {
6
6
  version: string;
7
7
  resolved?: string;
8
8
  integrity?: string;
9
+ registryName?: string;
9
10
  }
10
11
  /** npm registry package time information */
11
12
  interface PackageTimeInfo {
@@ -17,6 +18,7 @@ interface PackageTimeInfo {
17
18
  interface PackageCheckResult {
18
19
  name: string;
19
20
  version: string;
21
+ registryName?: string;
20
22
  publishedAt: Date;
21
23
  isNew: boolean;
22
24
  daysAgo: number;
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  parseMinimumReleaseAge,
8
8
  parsePackageLock,
9
9
  parseYarnLock
10
- } from "./chunk-3YXJPGA4.js";
10
+ } from "./chunk-WYSKMPXQ.js";
11
11
  export {
12
12
  NpmRegistryClient,
13
13
  analyzeLockfile,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "check-npm-lockfile",
3
- "version": "0.0.3",
3
+ "version": "0.1.0",
4
4
  "description": "Detect recently published npm packages in lockfiles for supply chain attack prevention",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -20,7 +20,7 @@
20
20
  "author": "Masahiro Saito",
21
21
  "license": "MIT",
22
22
  "engines": {
23
- "node": ">=20.0.0"
23
+ "node": ">=22.0.0"
24
24
  },
25
25
  "dependencies": {
26
26
  "@yarnpkg/lockfile": "^1.1.0",
@@ -31,7 +31,7 @@
31
31
  "yaml": "^2.7.0"
32
32
  },
33
33
  "devDependencies": {
34
- "@types/node": "^20.19.27",
34
+ "@types/node": "^22.10.5",
35
35
  "tsup": "^8.3.5",
36
36
  "typescript": "^5.7.2"
37
37
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/parsers/yarn-lock.ts","../src/parsers/package-lock.ts","../src/registry/npm-client.ts","../src/analyzer/index.ts","../src/output/console.ts","../src/output/json.ts","../src/output/index.ts"],"sourcesContent":["import lockfile from \"@yarnpkg/lockfile\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { ParsedPackage } from \"../types/index.js\";\n\nexport function detectYarnVersion(content: string): \"yarn-v1\" | \"yarn-berry\" {\n if (content.includes(\"__metadata:\")) {\n return \"yarn-berry\";\n }\n return \"yarn-v1\";\n}\n\nexport function parseYarnLockV1(content: string): ParsedPackage[] {\n const result = lockfile.parse(content);\n\n if (result.type !== \"success\") {\n throw new Error(\"Failed to parse yarn.lock file\");\n }\n\n const packages: ParsedPackage[] = [];\n const seen = new Set<string>();\n\n for (const [key, value] of Object.entries(result.object)) {\n const match = key.match(/^(@?[^@]+)@/);\n if (!match) continue;\n\n const name = match[1];\n const version = (value as { version: string }).version;\n const uniqueKey = `${name}@${version}`;\n\n if (seen.has(uniqueKey)) continue;\n seen.add(uniqueKey);\n\n packages.push({\n name,\n version,\n resolved: (value as { resolved?: string }).resolved,\n integrity: (value as { integrity?: string }).integrity,\n });\n }\n\n return packages;\n}\n\nexport function parseYarnLockBerry(content: string): ParsedPackage[] {\n const parsed = parseYaml(content) as Record<string, unknown>;\n const packages: ParsedPackage[] = [];\n const seen = new Set<string>();\n\n for (const [key, value] of Object.entries(parsed)) {\n if (key === \"__metadata\") continue;\n\n const descriptors = key.split(\", \");\n\n for (const descriptor of descriptors) {\n const match = descriptor.match(/^(@?[^@]+)@/);\n if (!match) continue;\n\n const name = match[1];\n const version = (value as { version: string }).version;\n const uniqueKey = `${name}@${version}`;\n\n if (seen.has(uniqueKey)) continue;\n seen.add(uniqueKey);\n\n packages.push({\n name,\n version,\n resolved: (value as { resolution?: string }).resolution,\n integrity: (value as { checksum?: string }).checksum,\n });\n\n break;\n }\n }\n\n return packages;\n}\n\nexport function parseYarnLock(content: string): {\n packages: ParsedPackage[];\n version: \"yarn-v1\" | \"yarn-berry\";\n} {\n const version = detectYarnVersion(content);\n const packages =\n version === \"yarn-v1\"\n ? parseYarnLockV1(content)\n : parseYarnLockBerry(content);\n return { packages, version };\n}\n","import type { ParsedPackage } from \"../types/index.js\";\n\ninterface PackageLockV2 {\n lockfileVersion: number;\n packages: Record<\n string,\n {\n version: string;\n resolved?: string;\n integrity?: string;\n }\n >;\n}\n\ninterface PackageLockV1 {\n lockfileVersion: 1;\n dependencies: Record<\n string,\n {\n version: string;\n resolved?: string;\n integrity?: string;\n dependencies?: Record<string, unknown>;\n }\n >;\n}\n\nexport function parsePackageLock(content: string): ParsedPackage[] {\n const parsed = JSON.parse(content) as { lockfileVersion?: number };\n const lockfileVersion = parsed.lockfileVersion || 1;\n\n if (lockfileVersion >= 2) {\n return parsePackageLockV2(parsed as PackageLockV2);\n }\n\n return parsePackageLockV1(parsed as PackageLockV1);\n}\n\nfunction parsePackageLockV2(data: PackageLockV2): ParsedPackage[] {\n const packages: ParsedPackage[] = [];\n\n for (const [path, info] of Object.entries(data.packages || {})) {\n if (path === \"\") continue;\n\n const segments = path.split(\"node_modules/\");\n const packageName = segments[segments.length - 1];\n\n if (!packageName || !info.version) continue;\n\n packages.push({\n name: packageName,\n version: info.version,\n resolved: info.resolved,\n integrity: info.integrity,\n });\n }\n\n return deduplicatePackages(packages);\n}\n\nfunction parsePackageLockV1(data: PackageLockV1): ParsedPackage[] {\n const packages: ParsedPackage[] = [];\n\n function traverse(deps: Record<string, { version: string; resolved?: string; integrity?: string; dependencies?: Record<string, unknown> }>) {\n for (const [name, info] of Object.entries(deps)) {\n packages.push({\n name,\n version: info.version,\n resolved: info.resolved,\n integrity: info.integrity,\n });\n\n if (info.dependencies) {\n traverse(info.dependencies as typeof deps);\n }\n }\n }\n\n traverse(data.dependencies || {});\n return deduplicatePackages(packages);\n}\n\nfunction deduplicatePackages(packages: ParsedPackage[]): ParsedPackage[] {\n const seen = new Map<string, ParsedPackage>();\n\n for (const pkg of packages) {\n const key = `${pkg.name}@${pkg.version}`;\n if (!seen.has(key)) {\n seen.set(key, pkg);\n }\n }\n\n return Array.from(seen.values());\n}\n","import pLimit from \"p-limit\";\nimport type { PackageTimeInfo } from \"../types/index.js\";\n\nconst NPM_REGISTRY = \"https://registry.npmjs.org\";\n\nexport class NpmRegistryClient {\n private cache: Map<string, PackageTimeInfo> = new Map();\n private limiter: ReturnType<typeof pLimit>;\n private retryDelay = 1000;\n private maxRetries = 3;\n\n constructor(concurrency = 10) {\n this.limiter = pLimit(concurrency);\n }\n\n async getPackageTime(name: string): Promise<PackageTimeInfo> {\n const cached = this.cache.get(name);\n if (cached) return cached;\n\n return this.limiter(async () => {\n const cachedAfterWait = this.cache.get(name);\n if (cachedAfterWait) return cachedAfterWait;\n\n const data = await this.fetchWithRetry(name);\n this.cache.set(name, data);\n return data;\n });\n }\n\n private async fetchWithRetry(\n name: string,\n attempt = 1\n ): Promise<PackageTimeInfo> {\n const url = `${NPM_REGISTRY}/${encodeURIComponent(name).replace(\"%40\", \"@\")}`;\n\n try {\n const response = await fetch(url, {\n headers: {\n Accept: \"application/json\",\n },\n });\n\n if (response.status === 429) {\n if (attempt <= this.maxRetries) {\n const delay = this.retryDelay * Math.pow(2, attempt - 1);\n await this.sleep(delay);\n return this.fetchWithRetry(name, attempt + 1);\n }\n throw new Error(`Rate limited after ${this.maxRetries} retries`);\n }\n\n if (response.status === 404) {\n throw new Error(`Package not found: ${name}`);\n }\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const data = (await response.json()) as { time: PackageTimeInfo };\n return data.time;\n } catch (error) {\n if (attempt <= this.maxRetries && this.isRetryableError(error)) {\n const delay = this.retryDelay * Math.pow(2, attempt - 1);\n await this.sleep(delay);\n return this.fetchWithRetry(name, attempt + 1);\n }\n throw error;\n }\n }\n\n private isRetryableError(error: unknown): boolean {\n if (error instanceof Error) {\n return (\n error.message.includes(\"ECONNRESET\") ||\n error.message.includes(\"ETIMEDOUT\") ||\n error.message.includes(\"fetch failed\")\n );\n }\n return false;\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import { readFileSync, existsSync } from \"fs\";\nimport { resolve, basename } from \"path\";\nimport { parseYarnLock } from \"../parsers/yarn-lock.js\";\nimport { parsePackageLock } from \"../parsers/package-lock.js\";\nimport { NpmRegistryClient } from \"../registry/npm-client.js\";\nimport type {\n ParsedPackage,\n AnalysisResult,\n PackageCheckResult,\n PackageError,\n CLIOptions,\n LockfileType,\n PackageTimeInfo,\n} from \"../types/index.js\";\n\nexport function parseMinimumReleaseAge(value: string): number {\n const match = value.match(/^(\\d+)\\s*(days?|hours?|minutes?)?$/i);\n if (!match) {\n throw new Error(\n `Invalid minimumReleaseAge format: \"${value}\". Use format like \"3 days\", \"7 days\", or \"24 hours\"`\n );\n }\n\n const num = parseInt(match[1], 10);\n const unit = (match[2] || \"days\").toLowerCase();\n\n if (unit.startsWith(\"day\")) {\n return num;\n } else if (unit.startsWith(\"hour\")) {\n return num / 24;\n } else if (unit.startsWith(\"minute\")) {\n return num / (24 * 60);\n }\n\n return num;\n}\n\nexport async function analyzeLockfile(\n lockfilePath: string | undefined,\n options: CLIOptions,\n onProgress?: (current: number, total: number) => void\n): Promise<AnalysisResult> {\n const resolvedPath = resolveLockfilePath(lockfilePath);\n const content = readFileSync(resolvedPath, \"utf-8\");\n\n const { packages, lockfileType } = parseLockfile(resolvedPath, content);\n\n const filteredPackages = packages.filter(\n (pkg) => !options.exclude.includes(pkg.name)\n );\n\n const client = new NpmRegistryClient(options.concurrency);\n const thresholdDays = parseMinimumReleaseAge(options.minimumReleaseAge);\n const thresholdDate = new Date();\n thresholdDate.setDate(thresholdDate.getDate() - thresholdDays);\n\n const recentPackages: PackageCheckResult[] = [];\n const errors: PackageError[] = [];\n\n const total = filteredPackages.length;\n let processed = 0;\n\n const checkPromises = filteredPackages.map(async (pkg) => {\n try {\n const timeInfo = await client.getPackageTime(pkg.name);\n const publishedAt = new Date(timeInfo[pkg.version]);\n\n if (isNaN(publishedAt.getTime())) {\n throw new Error(`Invalid publish date for version ${pkg.version}`);\n }\n\n const daysAgo = Math.floor(\n (Date.now() - publishedAt.getTime()) / (1000 * 60 * 60 * 24)\n );\n\n const isWithinThreshold = publishedAt >= thresholdDate;\n const isNew = isFirstVersion(timeInfo, pkg.version);\n\n if (isWithinThreshold) {\n recentPackages.push({\n name: pkg.name,\n version: pkg.version,\n publishedAt,\n isNew,\n daysAgo,\n isWithinThreshold,\n });\n }\n } catch (error) {\n errors.push({\n name: pkg.name,\n version: pkg.version,\n error: error instanceof Error ? error.message : String(error),\n });\n } finally {\n processed++;\n onProgress?.(processed, total);\n }\n });\n\n await Promise.all(checkPromises);\n\n recentPackages.sort(\n (a, b) => b.publishedAt.getTime() - a.publishedAt.getTime()\n );\n\n return {\n lockfileType,\n lockfilePath: resolvedPath,\n totalPackages: filteredPackages.length,\n checkedPackages: filteredPackages.length - errors.length,\n recentPackages,\n errors,\n analysisDate: new Date(),\n thresholdDays,\n };\n}\n\nfunction resolveLockfilePath(path?: string): string {\n if (path) {\n const resolved = resolve(path);\n if (!existsSync(resolved)) {\n throw new Error(`Lockfile not found: ${resolved}`);\n }\n return resolved;\n }\n\n const candidates = [\"yarn.lock\", \"package-lock.json\"];\n\n for (const candidate of candidates) {\n const resolved = resolve(candidate);\n if (existsSync(resolved)) {\n return resolved;\n }\n }\n\n throw new Error(\n \"No lockfile found. Please specify a path or run in a directory with yarn.lock or package-lock.json\"\n );\n}\n\nfunction parseLockfile(\n path: string,\n content: string\n): { packages: ParsedPackage[]; lockfileType: LockfileType } {\n const filename = basename(path);\n\n if (filename === \"yarn.lock\") {\n const { packages, version } = parseYarnLock(content);\n return { packages, lockfileType: version };\n }\n\n if (filename === \"package-lock.json\") {\n return {\n packages: parsePackageLock(content),\n lockfileType: \"npm\",\n };\n }\n\n throw new Error(`Unsupported lockfile: ${filename}`);\n}\n\nfunction isFirstVersion(\n timeInfo: PackageTimeInfo,\n version: string\n): boolean {\n const versions = Object.keys(timeInfo).filter(\n (k) => k !== \"created\" && k !== \"modified\"\n );\n\n if (versions.length === 0) return true;\n\n let earliestVersion = versions[0];\n let earliestDate = new Date(timeInfo[versions[0]]);\n\n for (const v of versions) {\n const date = new Date(timeInfo[v]);\n if (date < earliestDate) {\n earliestDate = date;\n earliestVersion = v;\n }\n }\n\n return version === earliestVersion;\n}\n","import chalk from \"chalk\";\nimport type { AnalysisResult } from \"../types/index.js\";\n\nexport function formatConsole(result: AnalysisResult): void {\n console.log();\n console.log(chalk.bold(\"Lockfile Analysis Report\"));\n console.log(chalk.gray(\"-\".repeat(50)));\n console.log(`File: ${chalk.cyan(result.lockfilePath)}`);\n console.log(`Type: ${chalk.cyan(result.lockfileType)}`);\n console.log(`Threshold: ${chalk.yellow(result.thresholdDays)} days`);\n console.log(`Total packages: ${result.totalPackages}`);\n console.log(`Checked: ${result.checkedPackages}`);\n console.log();\n\n if (result.recentPackages.length === 0) {\n console.log(chalk.green(\"No recently published packages found.\"));\n } else {\n console.log(\n chalk.red.bold(\n `Found ${result.recentPackages.length} package(s) published within ${result.thresholdDays} days:`\n )\n );\n console.log();\n\n for (const pkg of result.recentPackages) {\n const newBadge = pkg.isNew ? chalk.bgRed.white(\" NEW \") + \" \" : \" \";\n const daysLabel =\n pkg.daysAgo === 0\n ? \"today\"\n : pkg.daysAgo === 1\n ? \"1 day ago\"\n : `${pkg.daysAgo} days ago`;\n\n console.log(\n `${newBadge}${chalk.bold(pkg.name)}@${chalk.yellow(pkg.version)}`\n );\n console.log(\n ` Published: ${chalk.gray(pkg.publishedAt.toISOString())} (${chalk.yellow(daysLabel)})`\n );\n }\n }\n\n if (result.errors.length > 0) {\n console.log();\n console.log(\n chalk.yellow(\n `Warnings: ${result.errors.length} package(s) could not be checked`\n )\n );\n\n for (const err of result.errors) {\n console.log(chalk.gray(` - ${err.name}@${err.version}: ${err.error}`));\n }\n }\n\n console.log();\n}\n","import type { AnalysisResult } from \"../types/index.js\";\n\nexport function formatJson(result: AnalysisResult): void {\n const output = {\n ...result,\n recentPackages: result.recentPackages.map((pkg) => ({\n ...pkg,\n publishedAt: pkg.publishedAt.toISOString(),\n })),\n analysisDate: result.analysisDate.toISOString(),\n };\n\n console.log(JSON.stringify(output, null, 2));\n}\n","import type { AnalysisResult } from \"../types/index.js\";\nimport { formatConsole } from \"./console.js\";\nimport { formatJson } from \"./json.js\";\n\nexport function formatOutput(\n result: AnalysisResult,\n format: \"console\" | \"json\"\n): void {\n if (format === \"json\") {\n formatJson(result);\n } else {\n formatConsole(result);\n }\n}\n\nexport { formatConsole } from \"./console.js\";\nexport { formatJson } from \"./json.js\";\n"],"mappings":"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","names":["resolve"]}