@agntn/registries 0.2.0 → 0.3.1

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 (113) hide show
  1. package/README.md +26 -3
  2. package/dist/THIRD-PARTY-LICENSES.md +36 -0
  3. package/dist/_chunks/cache.mjs +15 -0
  4. package/dist/{cache/index.mjs.map → _chunks/cache.mjs.map} +1 -1
  5. package/dist/{commands/cache.mjs → _chunks/cache2.mjs} +6 -8
  6. package/dist/_chunks/cache2.mjs.map +1 -0
  7. package/dist/{cache → _chunks}/cached-registry.mjs +12 -8
  8. package/dist/_chunks/cached-registry.mjs.map +1 -0
  9. package/dist/{commands → _chunks}/deps.mjs +20 -14
  10. package/dist/_chunks/deps.mjs.map +1 -0
  11. package/dist/_chunks/helpers.mjs +53 -19
  12. package/dist/_chunks/helpers.mjs.map +1 -1
  13. package/dist/_chunks/index.d.mts +9 -23
  14. package/dist/_chunks/index.d.mts.map +1 -1
  15. package/dist/_chunks/index2.d.mts +156 -25
  16. package/dist/_chunks/index2.d.mts.map +1 -1
  17. package/dist/_chunks/index3.d.mts +173 -3
  18. package/dist/_chunks/index3.d.mts.map +1 -1
  19. package/dist/_chunks/info.mjs +105 -0
  20. package/dist/_chunks/info.mjs.map +1 -0
  21. package/dist/_chunks/libs/typebox.mjs +278 -0
  22. package/dist/_chunks/libs/typebox.mjs.map +1 -0
  23. package/dist/_chunks/lockfile.mjs +183 -0
  24. package/dist/_chunks/lockfile.mjs.map +1 -0
  25. package/dist/_chunks/maintainers.mjs +53 -0
  26. package/dist/_chunks/maintainers.mjs.map +1 -0
  27. package/dist/_chunks/mcp.mjs +15 -0
  28. package/dist/_chunks/mcp.mjs.map +1 -0
  29. package/dist/_chunks/registries.mjs +514 -245
  30. package/dist/_chunks/registries.mjs.map +1 -1
  31. package/dist/_chunks/registry.d.mts +121 -10
  32. package/dist/_chunks/registry.d.mts.map +1 -1
  33. package/dist/_chunks/registry.mjs +121 -31
  34. package/dist/_chunks/registry.mjs.map +1 -1
  35. package/dist/{commands → _chunks}/shared.mjs +15 -8
  36. package/dist/_chunks/shared.mjs.map +1 -0
  37. package/dist/_chunks/tool-operations.mjs +63 -0
  38. package/dist/_chunks/tool-operations.mjs.map +1 -0
  39. package/dist/_chunks/version.mjs +4 -0
  40. package/dist/_chunks/version.mjs.map +1 -0
  41. package/dist/{commands → _chunks}/versions.mjs +10 -9
  42. package/dist/_chunks/versions.mjs.map +1 -0
  43. package/dist/ai.d.mts +2 -8
  44. package/dist/ai.d.mts.map +1 -1
  45. package/dist/ai.mjs +0 -1
  46. package/dist/ai.mjs.map +1 -1
  47. package/dist/cache/index.d.mts +1 -6
  48. package/dist/cache/index.mjs +4 -11
  49. package/dist/cli.mjs +9 -7
  50. package/dist/cli.mjs.map +1 -1
  51. package/dist/index.d.mts +3 -9
  52. package/dist/index.mjs +4 -7
  53. package/dist/mcp.d.mts +7 -0
  54. package/dist/mcp.d.mts.map +1 -0
  55. package/dist/mcp.mjs +155 -0
  56. package/dist/mcp.mjs.map +1 -0
  57. package/dist/registries/index.d.mts +0 -1
  58. package/dist/registries/index.mjs +0 -1
  59. package/dist/tool-operations.d.mts +36 -0
  60. package/dist/tool-operations.d.mts.map +1 -0
  61. package/dist/tool-operations.mjs +5 -0
  62. package/package.json +55 -9
  63. package/packages/omp/extensions/registries.ts +112 -0
  64. package/packages/pi/extensions/registries.ts +125 -0
  65. package/dist/_chunks/cached-registry.d.mts +0 -35
  66. package/dist/_chunks/cached-registry.d.mts.map +0 -1
  67. package/dist/_chunks/errors.d.mts +0 -90
  68. package/dist/_chunks/errors.d.mts.map +0 -1
  69. package/dist/_chunks/lockfile.d.mts +0 -50
  70. package/dist/_chunks/lockfile.d.mts.map +0 -1
  71. package/dist/_chunks/paths.d.mts +0 -11
  72. package/dist/_chunks/paths.d.mts.map +0 -1
  73. package/dist/_chunks/purl.mjs +0 -192
  74. package/dist/_chunks/purl.mjs.map +0 -1
  75. package/dist/_chunks/storage.d.mts +0 -22
  76. package/dist/_chunks/storage.d.mts.map +0 -1
  77. package/dist/_chunks/types.d.mts +0 -73
  78. package/dist/_chunks/types.d.mts.map +0 -1
  79. package/dist/cache/cached-registry.d.mts +0 -4
  80. package/dist/cache/cached-registry.mjs.map +0 -1
  81. package/dist/cache/lockfile.d.mts +0 -2
  82. package/dist/cache/lockfile.mjs +0 -68
  83. package/dist/cache/lockfile.mjs.map +0 -1
  84. package/dist/cache/paths.d.mts +0 -2
  85. package/dist/cache/paths.mjs +0 -26
  86. package/dist/cache/paths.mjs.map +0 -1
  87. package/dist/cache/storage.d.mts +0 -2
  88. package/dist/cache/storage.mjs +0 -40
  89. package/dist/cache/storage.mjs.map +0 -1
  90. package/dist/commands/cache.d.mts +0 -7
  91. package/dist/commands/cache.d.mts.map +0 -1
  92. package/dist/commands/cache.mjs.map +0 -1
  93. package/dist/commands/deps.d.mts +0 -23
  94. package/dist/commands/deps.d.mts.map +0 -1
  95. package/dist/commands/deps.mjs.map +0 -1
  96. package/dist/commands/info.d.mts +0 -26
  97. package/dist/commands/info.d.mts.map +0 -1
  98. package/dist/commands/info.mjs +0 -54
  99. package/dist/commands/info.mjs.map +0 -1
  100. package/dist/commands/maintainers.d.mts +0 -23
  101. package/dist/commands/maintainers.d.mts.map +0 -1
  102. package/dist/commands/maintainers.mjs +0 -46
  103. package/dist/commands/maintainers.mjs.map +0 -1
  104. package/dist/commands/shared.d.mts +0 -27
  105. package/dist/commands/shared.d.mts.map +0 -1
  106. package/dist/commands/shared.mjs.map +0 -1
  107. package/dist/commands/versions.d.mts +0 -31
  108. package/dist/commands/versions.d.mts.map +0 -1
  109. package/dist/commands/versions.mjs.map +0 -1
  110. package/dist/core/index.d.mts +0 -4
  111. package/dist/core/index.mjs +0 -3
  112. package/dist/types.d.mts +0 -3
  113. package/dist/types.mjs +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"purl.mjs","names":[],"sources":["../../src/core/license.ts","../../src/core/repository.ts","../../src/core/purl.ts"],"sourcesContent":["/**\n * Normalize a license string to SPDX expression.\n *\n * Handles common variations: \"MIT License\" → \"MIT\", \"Apache 2.0\" → \"Apache-2.0\".\n * Passes through already-valid SPDX identifiers unchanged.\n */\nexport function normalizeLicense(raw: string | null | undefined): string {\n if (!raw) return \"\";\n\n const trimmed = raw.trim();\n if (!trimmed) return \"\";\n\n // Common mappings\n const lower = trimmed.toLowerCase();\n const known = LICENSE_MAP.get(lower);\n if (known) return known;\n\n // Already looks like SPDX — return as-is\n return trimmed;\n}\n\nconst LICENSE_MAP = new Map<string, string>([\n [\"mit license\", \"MIT\"],\n [\"mit\", \"MIT\"],\n [\"apache license 2.0\", \"Apache-2.0\"],\n [\"apache 2.0\", \"Apache-2.0\"],\n [\"apache-2.0\", \"Apache-2.0\"],\n [\"apache license, version 2.0\", \"Apache-2.0\"],\n [\"apache2\", \"Apache-2.0\"],\n [\"bsd-2-clause\", \"BSD-2-Clause\"],\n [\"bsd-3-clause\", \"BSD-3-Clause\"],\n [\"bsd 2-clause\", \"BSD-2-Clause\"],\n [\"bsd 3-clause\", \"BSD-3-Clause\"],\n [\"simplified bsd license\", \"BSD-2-Clause\"],\n [\"new bsd license\", \"BSD-3-Clause\"],\n [\"isc license\", \"ISC\"],\n [\"isc\", \"ISC\"],\n [\"gpl-2.0\", \"GPL-2.0-only\"],\n [\"gpl-3.0\", \"GPL-3.0-only\"],\n [\"gpl-2.0-only\", \"GPL-2.0-only\"],\n [\"gpl-3.0-only\", \"GPL-3.0-only\"],\n [\"lgpl-2.1\", \"LGPL-2.1-only\"],\n [\"lgpl-3.0\", \"LGPL-3.0-only\"],\n [\"mpl-2.0\", \"MPL-2.0\"],\n [\"mozilla public license 2.0\", \"MPL-2.0\"],\n [\"unlicense\", \"Unlicense\"],\n [\"the unlicense\", \"Unlicense\"],\n [\"cc0-1.0\", \"CC0-1.0\"],\n [\"cc0\", \"CC0-1.0\"],\n [\"public domain\", \"Unlicense\"],\n [\"zlib\", \"Zlib\"],\n [\"wtfpl\", \"WTFPL\"],\n [\"artistic-2.0\", \"Artistic-2.0\"],\n [\"boost software license 1.0\", \"BSL-1.0\"],\n [\"bsl-1.0\", \"BSL-1.0\"],\n]);\n\n/**\n * Combine multiple license strings into a single SPDX expression.\n *\n * Default operator is OR (disjunctive, user picks one).\n * Pass \"AND\" for ecosystems where multiple licenses mean all apply (e.g. Arch Linux).\n */\nexport function combineLicenses(\n licenses: (string | null | undefined)[],\n operator: \"OR\" | \"AND\" = \"OR\",\n): string {\n const normalized = licenses.map((l) => normalizeLicense(l)).filter(Boolean);\n\n if (normalized.length === 0) return \"\";\n if (normalized.length === 1) return normalized[0]!;\n return normalized.join(` ${operator} `);\n}\n","/**\n * Normalize a repository URL to a clean HTTPS git URL.\n *\n * Handles various formats:\n * - \"git+https://github.com/foo/bar.git\" → \"https://github.com/foo/bar\"\n * - \"git://github.com/foo/bar\" → \"https://github.com/foo/bar\"\n * - \"ssh://git@github.com/foo/bar.git\" → \"https://github.com/foo/bar\"\n * - \"github:foo/bar\" → \"https://github.com/foo/bar\"\n * - { url: \"...\" } → extracted and normalized\n */\nexport function normalizeRepositoryURL(raw: unknown): string {\n if (!raw) return \"\";\n\n let url: string;\n\n if (typeof raw === \"string\") {\n url = raw;\n } else if (typeof raw === \"object\" && raw !== null) {\n const obj = raw as Record<string, unknown>;\n if (typeof obj[\"url\"] === \"string\") {\n url = obj[\"url\"];\n } else {\n return \"\";\n }\n } else {\n return \"\";\n }\n\n url = url.trim();\n if (!url) return \"\";\n\n // GitHub shorthand: \"github:user/repo\"\n if (url.startsWith(\"github:\")) {\n url = `https://github.com/${url.slice(7)}`;\n }\n\n // GitLab shorthand\n if (url.startsWith(\"gitlab:\")) {\n url = `https://gitlab.com/${url.slice(7)}`;\n }\n\n // Bitbucket shorthand\n if (url.startsWith(\"bitbucket:\")) {\n url = `https://bitbucket.org/${url.slice(10)}`;\n }\n\n // Strip \"git+\" prefix\n if (url.startsWith(\"git+\")) {\n url = url.slice(4);\n }\n\n // Convert git:// to https://\n if (url.startsWith(\"git://\")) {\n url = \"https://\" + url.slice(6);\n }\n\n // Convert ssh://git@host/... to https://host/...\n if (url.startsWith(\"ssh://git@\")) {\n url = \"https://\" + url.slice(10);\n }\n\n // Convert git@host:user/repo to https://host/user/repo\n const sshMatch = url.match(/^git@([^:]+):(.+)$/);\n if (sshMatch) {\n url = `https://${sshMatch[1]}/${sshMatch[2]}`;\n }\n\n // Strip trailing slash first so \".git/\" doesn't survive\n if (url.endsWith(\"/\")) {\n url = url.slice(0, -1);\n }\n\n // Strip .git suffix\n if (url.endsWith(\".git\")) {\n url = url.slice(0, -4);\n }\n\n return url;\n}\n","import type { ParsedPURL } from \"./types.ts\";\nimport type { Client } from \"./client.ts\";\nimport { create, type Registry } from \"./registry.ts\";\nimport { InvalidPURLError } from \"./errors.ts\";\n\n/** Decode a percent-encoded PURL component, throwing InvalidPURLError on malformed sequences. */\nfunction decodePURLComponent(purlStr: string, value: string): string {\n try {\n return decodeURIComponent(value);\n } catch {\n throw new InvalidPURLError(purlStr, \"malformed percent-encoding\");\n }\n}\n\n/**\n * Parse a PURL string into its components.\n *\n * Format: `pkg:<type>/<namespace>/<name>@<version>?<qualifiers>#<subpath>`\n *\n * @see https://github.com/package-url/purl-spec (ECMA-427)\n */\nexport function parsePURL(purlStr: string): ParsedPURL {\n if (!purlStr.startsWith(\"pkg:\")) {\n throw new InvalidPURLError(purlStr, 'must start with \"pkg:\"');\n }\n\n let remainder = purlStr.slice(4); // strip 'pkg:'\n\n // Extract subpath\n let subpath = \"\";\n const hashIdx = remainder.indexOf(\"#\");\n if (hashIdx !== -1) {\n subpath = remainder\n .slice(hashIdx + 1)\n .split(\"/\")\n .map((s) => decodePURLComponent(purlStr, s))\n .join(\"/\");\n remainder = remainder.slice(0, hashIdx);\n }\n\n // Extract qualifiers\n const qualifiers: Record<string, string> = {};\n const queryIdx = remainder.indexOf(\"?\");\n if (queryIdx !== -1) {\n const queryStr = remainder.slice(queryIdx + 1);\n remainder = remainder.slice(0, queryIdx);\n for (const pair of queryStr.split(\"&\")) {\n const eqIdx = pair.indexOf(\"=\");\n if (eqIdx !== -1) {\n qualifiers[decodePURLComponent(purlStr, pair.slice(0, eqIdx))] = decodePURLComponent(\n purlStr,\n pair.slice(eqIdx + 1),\n );\n }\n }\n }\n\n // Extract version — the version separator is the last '@' that appears\n // after the last '/', so scoped names like 'npm/@vue/core' are not mistaken\n // for having a version.\n let version = \"\";\n const lastSlashBeforeVersion = remainder.lastIndexOf(\"/\");\n const lastAtIdx = remainder.lastIndexOf(\"@\");\n if (lastAtIdx !== -1 && lastAtIdx > lastSlashBeforeVersion) {\n version = decodePURLComponent(purlStr, remainder.slice(lastAtIdx + 1));\n remainder = remainder.slice(0, lastAtIdx);\n }\n\n // Extract type\n const slashIdx = remainder.indexOf(\"/\");\n if (slashIdx === -1) {\n throw new InvalidPURLError(purlStr, \"missing type/name separator\");\n }\n\n const type = remainder.slice(0, slashIdx).toLowerCase();\n if (!type) {\n throw new InvalidPURLError(purlStr, \"empty type\");\n }\n\n const rest = remainder.slice(slashIdx + 1);\n if (!rest) {\n throw new InvalidPURLError(purlStr, \"empty name\");\n }\n\n // Extract namespace and name\n const lastSlashIdx = rest.lastIndexOf(\"/\");\n let namespace = \"\";\n let name: string;\n\n if (lastSlashIdx !== -1) {\n namespace = rest\n .slice(0, lastSlashIdx)\n .split(\"/\")\n .map((s) => decodePURLComponent(purlStr, s))\n .join(\"/\");\n name = decodePURLComponent(purlStr, rest.slice(lastSlashIdx + 1));\n } else {\n name = decodePURLComponent(purlStr, rest);\n }\n\n // Ecosystem-specific normalization per PURL spec\n if (type === \"pypi\") {\n name = name.toLowerCase().replace(/[-_.]+/g, \"-\");\n }\n\n if (type === \"alpm\") {\n name = name.toLowerCase();\n }\n\n return { type, namespace, name, version, qualifiers, subpath };\n}\n\n/** Build the full name from namespace + name (e.g., \"@scope/pkg\" for npm). */\nexport function fullName(parsed: ParsedPURL): string {\n if (parsed.namespace) {\n return `${parsed.namespace}/${parsed.name}`;\n }\n return parsed.name;\n}\n\n/** Create a registry instance from a PURL, returning [registry, name, version]. */\nexport function createFromPURL(purlStr: string, client?: Client): [Registry, string, string] {\n const parsed = parsePURL(purlStr);\n const baseURL = parsed.qualifiers[\"repository_url\"] ?? \"\";\n const reg = create(parsed.type, baseURL || undefined, client);\n return [reg, fullName(parsed), parsed.version];\n}\n\n/** Build a PURL string from components. Inverse of `parsePURL`. */\nexport function buildPURL(parts: {\n type: string;\n name: string;\n version?: string;\n namespace?: string;\n qualifiers?: Record<string, string>;\n subpath?: string;\n}): string {\n let purl = `pkg:${parts.type}/`;\n if (parts.namespace) {\n purl += `${parts.namespace\n .split(\"/\")\n .map((s) => encodeURIComponent(s))\n .join(\"/\")}/`;\n }\n purl += encodeURIComponent(parts.name);\n if (parts.version) {\n purl += `@${encodeURIComponent(parts.version)}`;\n }\n if (parts.qualifiers && Object.keys(parts.qualifiers).length > 0) {\n const qs = Object.entries(parts.qualifiers)\n .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)\n .join(\"&\");\n purl += `?${qs}`;\n }\n if (parts.subpath) {\n purl += `#${parts.subpath\n .split(\"/\")\n .map((s) => encodeURIComponent(s))\n .join(\"/\")}`;\n }\n return purl;\n}\n"],"mappings":"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"}
@@ -1,22 +0,0 @@
1
- import { Storage } from "unstorage";
2
-
3
- //#region src/cache/storage.d.ts
4
- /**
5
- * Configure a custom unstorage instance for @agntn/registries.
6
- * Call this before any cache operations to use a non-default driver
7
- * (e.g. Cloudflare KV, Redis, memory).
8
- */
9
- declare function configureStorage(storage: Storage): void;
10
- /** Get or create the shared storage instance. Uses configured storage or falls back to fs driver. */
11
- declare function getStorage(): Storage;
12
- /** Get a namespaced storage for a specific ecosystem (e.g. 'npm', 'cargo'). */
13
- declare function getEcosystemStorage(ecosystem: string): Storage;
14
- /** Compute a sha256 integrity hash of a JSON-serializable value. */
15
- declare function computeIntegrity(value: unknown): string;
16
- /** Dispose the storage instance. Call on process exit. */
17
- declare function disposeStorage(): Promise<void>;
18
- /** Clear all cached data. */
19
- declare function clearStorage(): Promise<void>;
20
- //#endregion
21
- export { getEcosystemStorage as a, disposeStorage as i, computeIntegrity as n, getStorage as o, configureStorage as r, clearStorage as t };
22
- //# sourceMappingURL=storage.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"storage.d.mts","names":[],"sources":["../../src/cache/storage.ts"],"mappings":";;;;;AAaA;;;iBAAgB,gBAAA,CAAiB,OAAA,EAAS,OAAA;;iBAK1B,UAAA,CAAA,GAAc,OAAA;;iBAUd,mBAAA,CAAoB,SAAA,WAAoB,OAAA;;iBAKxC,gBAAA,CAAiB,KAAA;AALjC;AAAA,iBAUsB,cAAA,CAAA,GAAkB,OAAA;;iBAQlB,YAAA,CAAA,GAAgB,OAAA"}
@@ -1,73 +0,0 @@
1
- //#region src/core/types.d.ts
2
- /** Normalized package metadata returned by any registry. */
3
- interface Package {
4
- name: string;
5
- description: string;
6
- homepage: string;
7
- documentation: string;
8
- repository: string;
9
- licenses: string;
10
- keywords: string[];
11
- namespace: string;
12
- latestVersion: string;
13
- metadata: Record<string, unknown>;
14
- }
15
- /** A single version entry of a package. */
16
- interface Version {
17
- number: string;
18
- publishedAt: Date | null;
19
- licenses: string;
20
- integrity: string;
21
- status: VersionStatus;
22
- metadata: Record<string, unknown>;
23
- }
24
- /** Dependency of a package version. */
25
- interface Dependency {
26
- name: string;
27
- requirements: string;
28
- scope: Scope;
29
- optional: boolean;
30
- }
31
- /** Maintainer / author of a package. */
32
- interface Maintainer {
33
- uuid: string;
34
- login: string;
35
- name: string;
36
- email: string;
37
- url: string;
38
- role: string;
39
- }
40
- type VersionStatus = "" | "yanked" | "deprecated" | "retracted";
41
- type Scope = "runtime" | "development" | "test" | "build" | "optional";
42
- /** URL builder for a specific registry. */
43
- interface URLBuilder {
44
- registry(name: string, version?: string): string;
45
- download(name: string, version: string): string;
46
- documentation(name: string, version?: string): string;
47
- readme(name: string, version?: string): string;
48
- purl(name: string, version?: string): string;
49
- }
50
- /** Options for the HTTP client. */
51
- interface ClientOptions {
52
- maxRetries?: number;
53
- baseDelay?: number;
54
- timeout?: number;
55
- rateLimiter?: RateLimiter;
56
- userAgent?: string;
57
- }
58
- /** Rate limiter interface — bring your own implementation. */
59
- interface RateLimiter {
60
- wait(signal?: AbortSignal): Promise<void>;
61
- }
62
- /** Parsed PURL components. */
63
- interface ParsedPURL {
64
- type: string;
65
- namespace: string;
66
- name: string;
67
- version: string;
68
- qualifiers: Record<string, string>;
69
- subpath: string;
70
- }
71
- //#endregion
72
- export { ParsedPURL as a, URLBuilder as c, Package as i, Version as l, Dependency as n, RateLimiter as o, Maintainer as r, Scope as s, ClientOptions as t, VersionStatus as u };
73
- //# sourceMappingURL=types.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/core/types.ts"],"mappings":";;UACiB,OAAA;EACf,IAAA;EACA,WAAA;EACA,QAAA;EACA,aAAA;EACA,UAAA;EACA,QAAA;EACA,QAAA;EACA,SAAA;EACA,aAAA;EACA,QAAA,EAAU,MAAA;AAAA;;UAIK,OAAA;EACf,MAAA;EACA,WAAA,EAAa,IAAA;EACb,QAAA;EACA,SAAA;EACA,MAAA,EAAQ,aAAA;EACR,QAAA,EAAU,MAAA;AAAA;;UAIK,UAAA;EACf,IAAA;EACA,YAAA;EACA,KAAA,EAAO,KAAA;EACP,QAAA;AAAA;;UAIe,UAAA;EACf,IAAA;EACA,KAAA;EACA,IAAA;EACA,KAAA;EACA,GAAA;EACA,IAAA;AAAA;AAAA,KAGU,aAAA;AAAA,KACA,KAAA;;UAGK,UAAA;EACf,QAAA,CAAS,IAAA,UAAc,OAAA;EACvB,QAAA,CAAS,IAAA,UAAc,OAAA;EACvB,aAAA,CAAc,IAAA,UAAc,OAAA;EAC5B,MAAA,CAAO,IAAA,UAAc,OAAA;EACrB,IAAA,CAAK,IAAA,UAAc,OAAA;AAAA;AAlBrB;AAAA,UAsBiB,aAAA;EACf,UAAA;EACA,SAAA;EACA,OAAA;EACA,WAAA,GAAc,WAAA;EACd,SAAA;AAAA;;UAIe,WAAA;EACf,IAAA,CAAK,MAAA,GAAS,WAAA,GAAc,OAAA;AAAA;AAvB9B;AAAA,UA2BiB,UAAA;EACf,IAAA;EACA,SAAA;EACA,IAAA;EACA,OAAA;EACA,UAAA,EAAY,MAAA;EACZ,OAAA;AAAA"}
@@ -1,4 +0,0 @@
1
- import "../_chunks/types.mjs";
2
- import "../_chunks/registry.mjs";
3
- import { t as CachedRegistry } from "../_chunks/cached-registry.mjs";
4
- export { CachedRegistry };
@@ -1 +0,0 @@
1
- {"version":3,"file":"cached-registry.mjs","names":[],"sources":["../../src/cache/cached-registry.ts"],"sourcesContent":["import type { Dependency, Maintainer, Package, URLBuilder, Version } from \"../core/types.ts\";\nimport { Registry } from \"../core/registry.ts\";\nimport { getStorage, computeIntegrity } from \"./storage.ts\";\nimport {\n readLockfile,\n writeLockfile,\n cacheKey,\n getFreshEntry,\n setEntry,\n DEFAULT_TTL,\n} from \"./lockfile.ts\";\nimport type { EntryType, LockfileEntry } from \"./lockfile.ts\";\nimport type { Storage } from \"unstorage\";\n\n/**\n * CachedRegistry wraps any Registry and adds caching backed by unstorage\n * with a lockfile for freshness tracking.\n *\n * Pass a custom `storage` to use a non-default driver (e.g. Cloudflare KV).\n * If omitted, uses the globally configured storage (see `configureStorage()`).\n */\nexport class CachedRegistry extends Registry {\n readonly inner: Registry;\n readonly storage: Storage;\n private readonly lockfileStorage: Storage;\n private readonly inflight = new Map<string, Promise<unknown>>();\n\n constructor(inner: Registry, storage?: Storage) {\n super();\n this.inner = inner;\n this.storage = storage ?? getStorage();\n this.lockfileStorage = storage ?? getStorage();\n }\n\n ecosystem(): string {\n return this.inner.ecosystem();\n }\n\n urls(): URLBuilder {\n return this.inner.urls();\n }\n\n async fetchPackage(name: string, signal?: AbortSignal): Promise<Package> {\n return this.cached<Package>(\n name,\n \"package\",\n undefined,\n () => this.inner.fetchPackage(name, signal),\n signal,\n (value) => ({ latestVersion: value.latestVersion }),\n );\n }\n\n async fetchVersions(name: string, signal?: AbortSignal): Promise<Version[]> {\n const versions = await this.cached<Version[]>(\n name,\n \"versions\",\n undefined,\n () => this.inner.fetchVersions(name, signal),\n signal,\n );\n // JSON round-trip through storage turns Date objects into ISO strings.\n // Revive them so consumers can safely call .getTime() / .toISOString().\n return versions.map((v) => ({\n ...v,\n publishedAt: v.publishedAt ? new Date(v.publishedAt as unknown as string) : null,\n }));\n }\n\n async fetchDependencies(\n name: string,\n version: string,\n signal?: AbortSignal,\n ): Promise<Dependency[]> {\n return this.cached<Dependency[]>(\n name,\n \"dependencies\",\n version,\n () => this.inner.fetchDependencies(name, version, signal),\n signal,\n );\n }\n\n async fetchMaintainers(name: string, signal?: AbortSignal): Promise<Maintainer[]> {\n return this.cached<Maintainer[]>(\n name,\n \"maintainers\",\n undefined,\n () => this.inner.fetchMaintainers(name, signal),\n signal,\n );\n }\n\n /**\n * Generic cache-through method:\n * 1. Check lockfile for fresh entry\n * 2. If fresh -> read from storage\n * 3. If stale/missing -> fetch, store, update lockfile\n */\n private async cached<T>(\n name: string,\n type: EntryType,\n version: string | undefined,\n fetcher: () => Promise<T>,\n signal: AbortSignal | undefined,\n extraMeta?: (value: T) => Record<string, unknown>,\n ): Promise<T> {\n const eco = this.inner.ecosystem();\n const key = cacheKey(eco, name, type, version);\n const storageKey = key;\n\n // 1. Check lockfile\n const lockfile = await readLockfile(this.lockfileStorage);\n const entry = getFreshEntry(lockfile, key);\n\n if (entry) {\n // 2. Read from storage\n const cached = await this.storage.getItem<T>(storageKey);\n if (cached !== null) {\n // Verify integrity\n const currentHash = computeIntegrity(cached);\n if (currentHash === entry.integrity) {\n return cached;\n }\n // Integrity mismatch - refetch\n }\n }\n\n // 3. Coalesce concurrent fetches for the same key (single-flight).\n // Skip dedup when caller provides an AbortSignal to avoid sharing\n // cancellation context across unrelated callers.\n if (!signal) {\n const pending = this.inflight.get(key);\n if (pending) {\n return pending as Promise<T>;\n }\n }\n\n const flight = (async () => {\n const value = await fetcher();\n\n // Persist to cache (best-effort - storage failures must not discard fetched data)\n const meta = extraMeta ? extraMeta(value) : {};\n const newEntry: LockfileEntry = {\n key,\n type,\n fetchedAt: Date.now(),\n ttl: DEFAULT_TTL[type],\n integrity: computeIntegrity(value),\n ...(\"latestVersion\" in meta ? { latestVersion: meta[\"latestVersion\"] as string } : {}),\n };\n try {\n await this.storage.setItem(storageKey, value as Record<string, unknown>);\n // Re-read lockfile before writing to avoid overwriting entries\n // added by concurrent calls for different keys.\n const freshLockfile = await readLockfile(this.lockfileStorage);\n setEntry(freshLockfile, newEntry);\n await writeLockfile(freshLockfile, this.lockfileStorage);\n } catch {\n // Storage I/O failed (disk full, permissions, remote driver timeout, etc.).\n // The data was already fetched successfully - return it anyway.\n }\n\n return value;\n })();\n\n if (!signal) {\n this.inflight.set(key, flight);\n }\n try {\n return await flight;\n } finally {\n if (!signal) {\n this.inflight.delete(key);\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;AAqBA,IAAa,iBAAb,cAAoC,SAAS;CAC3C;CACA;CACA;CACA,2BAA4B,IAAI,KAA+B;CAE/D,YAAY,OAAiB,SAAmB;AAC9C,SAAO;AACP,OAAK,QAAQ;AACb,OAAK,UAAU,WAAW,YAAY;AACtC,OAAK,kBAAkB,WAAW,YAAY;;CAGhD,YAAoB;AAClB,SAAO,KAAK,MAAM,WAAW;;CAG/B,OAAmB;AACjB,SAAO,KAAK,MAAM,MAAM;;CAG1B,MAAM,aAAa,MAAc,QAAwC;AACvE,SAAO,KAAK,OACV,MACA,WACA,KAAA,SACM,KAAK,MAAM,aAAa,MAAM,OAAO,EAC3C,SACC,WAAW,EAAE,eAAe,MAAM,eAAe,EACnD;;CAGH,MAAM,cAAc,MAAc,QAA0C;AAU1E,UATiB,MAAM,KAAK,OAC1B,MACA,YACA,KAAA,SACM,KAAK,MAAM,cAAc,MAAM,OAAO,EAC5C,OACD,EAGe,KAAK,OAAO;GAC1B,GAAG;GACH,aAAa,EAAE,cAAc,IAAI,KAAK,EAAE,YAAiC,GAAG;GAC7E,EAAE;;CAGL,MAAM,kBACJ,MACA,SACA,QACuB;AACvB,SAAO,KAAK,OACV,MACA,gBACA,eACM,KAAK,MAAM,kBAAkB,MAAM,SAAS,OAAO,EACzD,OACD;;CAGH,MAAM,iBAAiB,MAAc,QAA6C;AAChF,SAAO,KAAK,OACV,MACA,eACA,KAAA,SACM,KAAK,MAAM,iBAAiB,MAAM,OAAO,EAC/C,OACD;;;;;;;;CASH,MAAc,OACZ,MACA,MACA,SACA,SACA,QACA,WACY;EAEZ,MAAM,MAAM,SADA,KAAK,MAAM,WAAW,EACR,MAAM,MAAM,QAAQ;EAC9C,MAAM,aAAa;EAInB,MAAM,QAAQ,cADG,MAAM,aAAa,KAAK,gBAAgB,EACnB,IAAI;AAE1C,MAAI,OAAO;GAET,MAAM,SAAS,MAAM,KAAK,QAAQ,QAAW,WAAW;AACxD,OAAI,WAAW;QAEO,iBAAiB,OAAO,KACxB,MAAM,UACxB,QAAO;;;AASb,MAAI,CAAC,QAAQ;GACX,MAAM,UAAU,KAAK,SAAS,IAAI,IAAI;AACtC,OAAI,QACF,QAAO;;EAIX,MAAM,UAAU,YAAY;GAC1B,MAAM,QAAQ,MAAM,SAAS;GAG7B,MAAM,OAAO,YAAY,UAAU,MAAM,GAAG,EAAE;GAC9C,MAAM,WAA0B;IAC9B;IACA;IACA,WAAW,KAAK,KAAK;IACrB,KAAK,YAAY;IACjB,WAAW,iBAAiB,MAAM;IAClC,GAAI,mBAAmB,OAAO,EAAE,eAAe,KAAK,kBAA4B,GAAG,EAAA;IACpF;AACD,OAAI;AACF,UAAM,KAAK,QAAQ,QAAQ,YAAY,MAAiC;IAGxE,MAAM,gBAAgB,MAAM,aAAa,KAAK,gBAAgB;AAC9D,aAAS,eAAe,SAAS;AACjC,UAAM,cAAc,eAAe,KAAK,gBAAgB;WAClD;AAKR,UAAO;MACL;AAEJ,MAAI,CAAC,OACH,MAAK,SAAS,IAAI,KAAK,OAAO;AAEhC,MAAI;AACF,UAAO,MAAM;YACL;AACR,OAAI,CAAC,OACH,MAAK,SAAS,OAAO,IAAI"}
@@ -1,2 +0,0 @@
1
- import { a as cacheKey, c as pruneStale, d as setEntry, f as writeLockfile, i as LockfileEntry, l as readLockfile, n as EntryType, o as getFreshEntry, r as Lockfile, s as isFresh, t as DEFAULT_TTL, u as removeEntry } from "../_chunks/lockfile.mjs";
2
- export { DEFAULT_TTL, EntryType, Lockfile, LockfileEntry, cacheKey, getFreshEntry, isFresh, pruneStale, readLockfile, removeEntry, setEntry, writeLockfile };
@@ -1,68 +0,0 @@
1
- import { getStorage } from "./storage.mjs";
2
- const LOCKFILE_VERSION = 1;
3
- const LOCKFILE_KEY = "__lockfile__";
4
- /** Default TTL per data type (seconds). */
5
- const DEFAULT_TTL = {
6
- package: 3600,
7
- versions: 1800,
8
- dependencies: 86400,
9
- maintainers: 86400
10
- };
11
- function emptyLockfile() {
12
- return {
13
- version: LOCKFILE_VERSION,
14
- entries: {}
15
- };
16
- }
17
- /** Read the lockfile from storage. Returns empty lockfile if not found or invalid. */
18
- async function readLockfile(storage) {
19
- const s = storage ?? getStorage();
20
- try {
21
- const data = await s.getItem(LOCKFILE_KEY);
22
- if (!data || data.version !== LOCKFILE_VERSION) return emptyLockfile();
23
- return data;
24
- } catch {
25
- return emptyLockfile();
26
- }
27
- }
28
- /** Write the lockfile to storage. */
29
- async function writeLockfile(lockfile, storage) {
30
- await (storage ?? getStorage()).setItem(LOCKFILE_KEY, lockfile);
31
- }
32
- /** Build a cache key from ecosystem + name + type + optional version. */
33
- function cacheKey(ecosystem, name, type, version) {
34
- const base = `${ecosystem}:${name}:${type}`;
35
- return version ? `${base}:${version}` : base;
36
- }
37
- /** Check if a lockfile entry is still fresh. */
38
- function isFresh(entry) {
39
- const expiresAt = entry.fetchedAt + entry.ttl * 1e3;
40
- return Date.now() < expiresAt;
41
- }
42
- /** Get a lockfile entry if it exists and is fresh. Returns null otherwise. */
43
- function getFreshEntry(lockfile, key) {
44
- const entry = lockfile.entries[key];
45
- if (!entry) return null;
46
- if (!isFresh(entry)) return null;
47
- return entry;
48
- }
49
- /** Upsert an entry in the lockfile. Does NOT persist — call writeLockfile() after. */
50
- function setEntry(lockfile, entry) {
51
- lockfile.entries[entry.key] = entry;
52
- }
53
- /** Remove an entry from the lockfile. */
54
- function removeEntry(lockfile, key) {
55
- delete lockfile.entries[key];
56
- }
57
- /** Remove all stale entries from the lockfile. Returns count of removed entries. */
58
- function pruneStale(lockfile) {
59
- let removed = 0;
60
- for (const key of Object.keys(lockfile.entries)) if (!isFresh(lockfile.entries[key])) {
61
- delete lockfile.entries[key];
62
- removed++;
63
- }
64
- return removed;
65
- }
66
- export { DEFAULT_TTL, cacheKey, getFreshEntry, isFresh, pruneStale, readLockfile, removeEntry, setEntry, writeLockfile };
67
-
68
- //# sourceMappingURL=lockfile.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"lockfile.mjs","names":[],"sources":["../../src/cache/lockfile.ts"],"sourcesContent":["import type { Storage } from \"unstorage\";\nimport { getStorage } from \"./storage.ts\";\n\nconst LOCKFILE_VERSION = 1;\nconst LOCKFILE_KEY = \"__lockfile__\";\n\n/** Default TTL per data type (seconds). */\nexport const DEFAULT_TTL = {\n package: 3600, // 1 hour — package metadata changes rarely\n versions: 1800, // 30 min — new versions published more often\n dependencies: 86400, // 24 hours — deps of a specific version never change\n maintainers: 86400, // 24 hours\n} as const;\n\nexport type EntryType = keyof typeof DEFAULT_TTL;\n\n/** A single cached entry tracked in the lockfile. */\nexport interface LockfileEntry {\n /** PURL-style key: 'npm:lodash', 'cargo:serde' */\n key: string;\n /** What kind of data: package, versions, dependencies, maintainers */\n type: EntryType;\n /** Unix timestamp (ms) when fetched */\n fetchedAt: number;\n /** TTL in seconds */\n ttl: number;\n /** Latest version at time of caching (for package entries) */\n latestVersion?: string;\n /** Content hash (sha256 of JSON-serialized value) for integrity */\n integrity: string;\n}\n\n/** The full lockfile structure. */\nexport interface Lockfile {\n version: number;\n entries: Record<string, LockfileEntry>;\n}\n\nfunction emptyLockfile(): Lockfile {\n return { version: LOCKFILE_VERSION, entries: {} };\n}\n\n/** Read the lockfile from storage. Returns empty lockfile if not found or invalid. */\nexport async function readLockfile(storage?: Storage): Promise<Lockfile> {\n const s = storage ?? getStorage();\n try {\n const data = await s.getItem<Lockfile>(LOCKFILE_KEY);\n if (!data || data.version !== LOCKFILE_VERSION) return emptyLockfile();\n return data;\n } catch {\n return emptyLockfile();\n }\n}\n\n/** Write the lockfile to storage. */\nexport async function writeLockfile(lockfile: Lockfile, storage?: Storage): Promise<void> {\n const s = storage ?? getStorage();\n await s.setItem(LOCKFILE_KEY, lockfile);\n}\n\n/** Build a cache key from ecosystem + name + type + optional version. */\nexport function cacheKey(\n ecosystem: string,\n name: string,\n type: EntryType,\n version?: string,\n): string {\n const base = `${ecosystem}:${name}:${type}`;\n return version ? `${base}:${version}` : base;\n}\n\n/** Check if a lockfile entry is still fresh. */\nexport function isFresh(entry: LockfileEntry): boolean {\n const expiresAt = entry.fetchedAt + entry.ttl * 1000;\n return Date.now() < expiresAt;\n}\n\n/** Get a lockfile entry if it exists and is fresh. Returns null otherwise. */\nexport function getFreshEntry(lockfile: Lockfile, key: string): LockfileEntry | null {\n const entry = lockfile.entries[key];\n if (!entry) return null;\n if (!isFresh(entry)) return null;\n return entry;\n}\n\n/** Upsert an entry in the lockfile. Does NOT persist — call writeLockfile() after. */\nexport function setEntry(lockfile: Lockfile, entry: LockfileEntry): void {\n lockfile.entries[entry.key] = entry;\n}\n\n/** Remove an entry from the lockfile. */\nexport function removeEntry(lockfile: Lockfile, key: string): void {\n delete lockfile.entries[key];\n}\n\n/** Remove all stale entries from the lockfile. Returns count of removed entries. */\nexport function pruneStale(lockfile: Lockfile): number {\n let removed = 0;\n for (const key of Object.keys(lockfile.entries)) {\n if (!isFresh(lockfile.entries[key]!)) {\n delete lockfile.entries[key];\n removed++;\n }\n }\n return removed;\n}\n"],"mappings":";AAGA,MAAM,mBAAmB;AACzB,MAAM,eAAe;;AAGrB,MAAa,cAAc;CACzB,SAAS;CACT,UAAU;CACV,cAAc;CACd,aAAa;CACd;AA0BD,SAAS,gBAA0B;AACjC,QAAO;EAAE,SAAS;EAAkB,SAAS,EAAA;EAAI;;;AAInD,eAAsB,aAAa,SAAsC;CACvE,MAAM,IAAI,WAAW,YAAY;AACjC,KAAI;EACF,MAAM,OAAO,MAAM,EAAE,QAAkB,aAAa;AACpD,MAAI,CAAC,QAAQ,KAAK,YAAY,iBAAkB,QAAO,eAAe;AACtE,SAAO;SACD;AACN,SAAO,eAAe;;;;AAK1B,eAAsB,cAAc,UAAoB,SAAkC;AAExF,QADU,WAAW,YAAY,EACzB,QAAQ,cAAc,SAAS;;;AAIzC,SAAgB,SACd,WACA,MACA,MACA,SACQ;CACR,MAAM,OAAO,GAAG,UAAU,GAAG,KAAK,GAAG;AACrC,QAAO,UAAU,GAAG,KAAK,GAAG,YAAY;;;AAI1C,SAAgB,QAAQ,OAA+B;CACrD,MAAM,YAAY,MAAM,YAAY,MAAM,MAAM;AAChD,QAAO,KAAK,KAAK,GAAG;;;AAItB,SAAgB,cAAc,UAAoB,KAAmC;CACnF,MAAM,QAAQ,SAAS,QAAQ;AAC/B,KAAI,CAAC,MAAO,QAAO;AACnB,KAAI,CAAC,QAAQ,MAAM,CAAE,QAAO;AAC5B,QAAO;;;AAIT,SAAgB,SAAS,UAAoB,OAA4B;AACvE,UAAS,QAAQ,MAAM,OAAO;;;AAIhC,SAAgB,YAAY,UAAoB,KAAmB;AACjE,QAAO,SAAS,QAAQ;;;AAI1B,SAAgB,WAAW,UAA4B;CACrD,IAAI,UAAU;AACd,MAAK,MAAM,OAAO,OAAO,KAAK,SAAS,QAAQ,CAC7C,KAAI,CAAC,QAAQ,SAAS,QAAQ,KAAM,EAAE;AACpC,SAAO,SAAS,QAAQ;AACxB;;AAGJ,QAAO"}
@@ -1,2 +0,0 @@
1
- import { t as getCacheDir } from "../_chunks/paths.mjs";
2
- export { getCacheDir };
@@ -1,26 +0,0 @@
1
- import { homedir, platform } from "node:os";
2
- import { join } from "node:path";
3
- const APP_NAME = "registries";
4
- /**
5
- * Resolve the cache directory following platform conventions:
6
- * - Linux: $XDG_CACHE_HOME/registries or ~/.cache/registries
7
- * - macOS: ~/Library/Caches/registries
8
- * - Windows: %LOCALAPPDATA%/registries/cache
9
- */
10
- function getCacheDir() {
11
- const envOverride = process.env["REGISTRIES_CACHE_DIR"];
12
- if (envOverride) return envOverride;
13
- const os = platform();
14
- if (os === "darwin") return join(homedir(), "Library", "Caches", APP_NAME);
15
- if (os === "win32") {
16
- const localAppData = process.env["LOCALAPPDATA"];
17
- if (localAppData) return join(localAppData, APP_NAME, "cache");
18
- return join(homedir(), "AppData", "Local", APP_NAME, "cache");
19
- }
20
- const xdgCache = process.env["XDG_CACHE_HOME"];
21
- if (xdgCache) return join(xdgCache, APP_NAME);
22
- return join(homedir(), ".cache", APP_NAME);
23
- }
24
- export { getCacheDir };
25
-
26
- //# sourceMappingURL=paths.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"paths.mjs","names":[],"sources":["../../src/cache/paths.ts"],"sourcesContent":["import { homedir, platform } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst APP_NAME = \"registries\";\n\n/**\n * Resolve the cache directory following platform conventions:\n * - Linux: $XDG_CACHE_HOME/registries or ~/.cache/registries\n * - macOS: ~/Library/Caches/registries\n * - Windows: %LOCALAPPDATA%/registries/cache\n */\nexport function getCacheDir(): string {\n // Explicit override always wins\n const envOverride = process.env[\"REGISTRIES_CACHE_DIR\"];\n if (envOverride) return envOverride;\n\n const os = platform();\n\n if (os === \"darwin\") {\n return join(homedir(), \"Library\", \"Caches\", APP_NAME);\n }\n\n if (os === \"win32\") {\n const localAppData = process.env[\"LOCALAPPDATA\"];\n if (localAppData) return join(localAppData, APP_NAME, \"cache\");\n return join(homedir(), \"AppData\", \"Local\", APP_NAME, \"cache\");\n }\n\n // Linux / FreeBSD / other — XDG Base Directory\n const xdgCache = process.env[\"XDG_CACHE_HOME\"];\n if (xdgCache) return join(xdgCache, APP_NAME);\n return join(homedir(), \".cache\", APP_NAME);\n}\n"],"mappings":";;AAGA,MAAM,WAAW;;;;;;;AAQjB,SAAgB,cAAsB;CAEpC,MAAM,cAAc,QAAQ,IAAI;AAChC,KAAI,YAAa,QAAO;CAExB,MAAM,KAAK,UAAU;AAErB,KAAI,OAAO,SACT,QAAO,KAAK,SAAS,EAAE,WAAW,UAAU,SAAS;AAGvD,KAAI,OAAO,SAAS;EAClB,MAAM,eAAe,QAAQ,IAAI;AACjC,MAAI,aAAc,QAAO,KAAK,cAAc,UAAU,QAAQ;AAC9D,SAAO,KAAK,SAAS,EAAE,WAAW,SAAS,UAAU,QAAQ;;CAI/D,MAAM,WAAW,QAAQ,IAAI;AAC7B,KAAI,SAAU,QAAO,KAAK,UAAU,SAAS;AAC7C,QAAO,KAAK,SAAS,EAAE,UAAU,SAAS"}
@@ -1,2 +0,0 @@
1
- import { a as getEcosystemStorage, i as disposeStorage, n as computeIntegrity, o as getStorage, r as configureStorage, t as clearStorage } from "../_chunks/storage.mjs";
2
- export { clearStorage, computeIntegrity, configureStorage, disposeStorage, getEcosystemStorage, getStorage };
@@ -1,40 +0,0 @@
1
- import { getCacheDir } from "./paths.mjs";
2
- import { createStorage, prefixStorage } from "unstorage";
3
- import fsDriver from "unstorage/drivers/fs";
4
- import { hash } from "node:crypto";
5
- let _storage;
6
- /**
7
- * Configure a custom unstorage instance for @agntn/registries.
8
- * Call this before any cache operations to use a non-default driver
9
- * (e.g. Cloudflare KV, Redis, memory).
10
- */
11
- function configureStorage(storage) {
12
- _storage = storage;
13
- }
14
- /** Get or create the shared storage instance. Uses configured storage or falls back to fs driver. */
15
- function getStorage() {
16
- if (!_storage) _storage = createStorage({ driver: fsDriver({ base: getCacheDir() }) });
17
- return _storage;
18
- }
19
- /** Get a namespaced storage for a specific ecosystem (e.g. 'npm', 'cargo'). */
20
- function getEcosystemStorage(ecosystem) {
21
- return prefixStorage(getStorage(), ecosystem);
22
- }
23
- /** Compute a sha256 integrity hash of a JSON-serializable value. */
24
- function computeIntegrity(value) {
25
- return `sha256-${hash("sha256", JSON.stringify(value), "hex")}`;
26
- }
27
- /** Dispose the storage instance. Call on process exit. */
28
- async function disposeStorage() {
29
- if (_storage) {
30
- await _storage.dispose();
31
- _storage = void 0;
32
- }
33
- }
34
- /** Clear all cached data. */
35
- async function clearStorage() {
36
- await getStorage().clear();
37
- }
38
- export { clearStorage, computeIntegrity, configureStorage, disposeStorage, getEcosystemStorage, getStorage };
39
-
40
- //# sourceMappingURL=storage.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"storage.mjs","names":[],"sources":["../../src/cache/storage.ts"],"sourcesContent":["import { createStorage, prefixStorage } from \"unstorage\";\nimport fsDriver from \"unstorage/drivers/fs\";\nimport type { Storage } from \"unstorage\";\nimport { getCacheDir } from \"./paths.ts\";\nimport { hash } from \"node:crypto\";\n\nlet _storage: Storage | undefined;\n\n/**\n * Configure a custom unstorage instance for @agntn/registries.\n * Call this before any cache operations to use a non-default driver\n * (e.g. Cloudflare KV, Redis, memory).\n */\nexport function configureStorage(storage: Storage): void {\n _storage = storage;\n}\n\n/** Get or create the shared storage instance. Uses configured storage or falls back to fs driver. */\nexport function getStorage(): Storage {\n if (!_storage) {\n _storage = createStorage({\n driver: fsDriver({ base: getCacheDir() }),\n });\n }\n return _storage;\n}\n\n/** Get a namespaced storage for a specific ecosystem (e.g. 'npm', 'cargo'). */\nexport function getEcosystemStorage(ecosystem: string): Storage {\n return prefixStorage(getStorage(), ecosystem);\n}\n\n/** Compute a sha256 integrity hash of a JSON-serializable value. */\nexport function computeIntegrity(value: unknown): string {\n return `sha256-${hash(\"sha256\", JSON.stringify(value), \"hex\")}`;\n}\n\n/** Dispose the storage instance. Call on process exit. */\nexport async function disposeStorage(): Promise<void> {\n if (_storage) {\n await _storage.dispose();\n _storage = undefined;\n }\n}\n\n/** Clear all cached data. */\nexport async function clearStorage(): Promise<void> {\n await getStorage().clear();\n}\n"],"mappings":";;;;AAMA,IAAI;;;;;;AAOJ,SAAgB,iBAAiB,SAAwB;AACvD,YAAW;;;AAIb,SAAgB,aAAsB;AACpC,KAAI,CAAC,SACH,YAAW,cAAc,EACvB,QAAQ,SAAS,EAAE,MAAM,aAAa,EAAE,CAAC,EAC1C,CAAC;AAEJ,QAAO;;;AAIT,SAAgB,oBAAoB,WAA4B;AAC9D,QAAO,cAAc,YAAY,EAAE,UAAU;;;AAI/C,SAAgB,iBAAiB,OAAwB;AACvD,QAAO,UAAU,KAAK,UAAU,KAAK,UAAU,MAAM,EAAE,MAAM;;;AAI/D,eAAsB,iBAAgC;AACpD,KAAI,UAAU;AACZ,QAAM,SAAS,SAAS;AACxB,aAAW,KAAA;;;;AAKf,eAAsB,eAA8B;AAClD,OAAM,YAAY,CAAC,OAAO"}
@@ -1,7 +0,0 @@
1
- import * as citty from "citty";
2
-
3
- //#region src/commands/cache.d.ts
4
- declare const _default: citty.CommandDef<citty.ArgsDef>;
5
- //#endregion
6
- export { _default as default };
7
- //# sourceMappingURL=cache.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cache.d.mts","names":[],"sources":["../../src/commands/cache.ts"],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"cache.mjs","names":[],"sources":["../../src/commands/cache.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport consola from \"consola\";\nimport { getCacheDir } from \"../cache/paths.ts\";\nimport { clearStorage } from \"../cache/storage.ts\";\nimport { readLockfile, writeLockfile, pruneStale } from \"../cache/lockfile.ts\";\n\nexport default defineCommand({\n meta: {\n name: \"cache\",\n description: \"Manage the registries cache\",\n },\n subCommands: {\n clear: defineCommand({\n meta: {\n name: \"clear\",\n description: \"Remove all cached data\",\n },\n async run() {\n await clearStorage();\n await writeLockfile({ version: 1, entries: {} });\n consola.success(\"Cache cleared\");\n },\n }),\n path: defineCommand({\n meta: {\n name: \"path\",\n description: \"Show cache directory path\",\n },\n run() {\n console.log(getCacheDir());\n },\n }),\n status: defineCommand({\n meta: {\n name: \"status\",\n description: \"Show cache status and entry count\",\n },\n async run() {\n const lockfile = await readLockfile();\n const entries = Object.values(lockfile.entries);\n const fresh = entries.filter((e) => {\n const expiresAt = e.fetchedAt + e.ttl * 1000;\n return Date.now() < expiresAt;\n });\n const stale = entries.length - fresh.length;\n\n consola.log(\"\");\n consola.log(` \\x1b[1mCache status\\x1b[0m`);\n consola.log(` \\x1b[90mDirectory:\\x1b[0m ${getCacheDir()}`);\n consola.log(\n ` \\x1b[90mEntries:\\x1b[0m ${entries.length} total, ${fresh.length} fresh, ${stale} stale`,\n );\n consola.log(\"\");\n\n if (fresh.length > 0) {\n // Group by ecosystem\n const byEco = new Map<string, number>();\n for (const e of fresh) {\n const eco = e.key.split(\":\")[0]!;\n byEco.set(eco, (byEco.get(eco) ?? 0) + 1);\n }\n for (const [eco, count] of byEco) {\n consola.log(` \\x1b[36m${eco}\\x1b[0m: ${count} cached`);\n }\n consola.log(\"\");\n }\n },\n }),\n prune: defineCommand({\n meta: {\n name: \"prune\",\n description: \"Remove stale cache entries\",\n },\n async run() {\n const lockfile = await readLockfile();\n const removed = pruneStale(lockfile);\n await writeLockfile(lockfile);\n consola.success(`Pruned ${removed} stale entries`);\n },\n }),\n },\n});\n"],"mappings":";;;;;AAMA,IAAA,gBAAe,cAAc;CAC3B,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,aAAa;EACX,OAAO,cAAc;GACnB,MAAM;IACJ,MAAM;IACN,aAAa;IACd;GACD,MAAM,MAAM;AACV,UAAM,cAAc;AACpB,UAAM,cAAc;KAAE,SAAS;KAAG,SAAS,EAAA;KAAI,CAAC;AAChD,YAAQ,QAAQ,gBAAgB;;GAEnC,CAAC;EACF,MAAM,cAAc;GAClB,MAAM;IACJ,MAAM;IACN,aAAa;IACd;GACD,MAAM;AACJ,YAAQ,IAAI,aAAa,CAAC;;GAE7B,CAAC;EACF,QAAQ,cAAc;GACpB,MAAM;IACJ,MAAM;IACN,aAAa;IACd;GACD,MAAM,MAAM;IACV,MAAM,WAAW,MAAM,cAAc;IACrC,MAAM,UAAU,OAAO,OAAO,SAAS,QAAQ;IAC/C,MAAM,QAAQ,QAAQ,QAAQ,MAAM;KAClC,MAAM,YAAY,EAAE,YAAY,EAAE,MAAM;AACxC,YAAO,KAAK,KAAK,GAAG;MACpB;IACF,MAAM,QAAQ,QAAQ,SAAS,MAAM;AAErC,YAAQ,IAAI,GAAG;AACf,YAAQ,IAAI,+BAA+B;AAC3C,YAAQ,IAAI,gCAAgC,aAAa,GAAG;AAC5D,YAAQ,IACN,gCAAgC,QAAQ,OAAO,UAAU,MAAM,OAAO,UAAU,MAAM,QACvF;AACD,YAAQ,IAAI,GAAG;AAEf,QAAI,MAAM,SAAS,GAAG;KAEpB,MAAM,wBAAQ,IAAI,KAAqB;AACvC,UAAK,MAAM,KAAK,OAAO;MACrB,MAAM,MAAM,EAAE,IAAI,MAAM,IAAI,CAAC;AAC7B,YAAM,IAAI,MAAM,MAAM,IAAI,IAAI,IAAI,KAAK,EAAE;;AAE3C,UAAK,MAAM,CAAC,KAAK,UAAU,MACzB,SAAQ,IAAI,aAAa,IAAI,WAAW,MAAM,SAAS;AAEzD,aAAQ,IAAI,GAAG;;;GAGpB,CAAC;EACF,OAAO,cAAc;GACnB,MAAM;IACJ,MAAM;IACN,aAAa;IACd;GACD,MAAM,MAAM;IACV,MAAM,WAAW,MAAM,cAAc;IACrC,MAAM,UAAU,WAAW,SAAS;AACpC,UAAM,cAAc,SAAS;AAC7B,YAAQ,QAAQ,UAAU,QAAQ,gBAAgB;;GAErD,CAAA;;CAEJ,CAAC"}
@@ -1,23 +0,0 @@
1
- import * as citty from "citty";
2
-
3
- //#region src/commands/deps.d.ts
4
- declare const _default: citty.CommandDef<{
5
- readonly purl: {
6
- readonly type: "positional";
7
- readonly description: "Package PURL with version (e.g. pkg:npm/lodash@4.17.21, cargo/serde@1.0)";
8
- readonly required: true;
9
- };
10
- readonly json: {
11
- readonly type: "boolean";
12
- readonly description: "Output as JSON";
13
- readonly default: false;
14
- };
15
- readonly "no-cache": {
16
- readonly type: "boolean";
17
- readonly description: "Bypass cache, fetch fresh data";
18
- readonly default: false;
19
- };
20
- }>;
21
- //#endregion
22
- export { _default as default };
23
- //# sourceMappingURL=deps.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deps.d.mts","names":[],"sources":["../../src/commands/deps.ts"],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"deps.mjs","names":[],"sources":["../../src/commands/deps.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport consola from \"consola\";\nimport { sharedArgs, resolvePURL, withErrorHandling } from \"./shared.ts\";\n\nexport default defineCommand({\n meta: {\n name: \"deps\",\n description: \"List package dependencies\",\n },\n args: {\n ...sharedArgs,\n purl: {\n type: \"positional\",\n description: \"Package PURL with version (e.g. pkg:npm/lodash@4.17.21, cargo/serde@1.0)\",\n required: true,\n },\n },\n async run({ args }) {\n await withErrorHandling(async () => {\n const [reg, name, version] = resolvePURL(args.purl, !args[\"no-cache\"]);\n\n if (!version) {\n // Try to resolve latest version\n const pkg = await reg.fetchPackage(name);\n if (!pkg.latestVersion) {\n consola.error(\n \"PURL must include a version for dependency lookup, and no latest version found.\",\n );\n consola.info(\"Example: pkg:npm/lodash@4.17.21\");\n process.exit(1);\n }\n consola.info(`No version specified, using latest: ${pkg.latestVersion}`);\n const deps = await reg.fetchDependencies(name, pkg.latestVersion);\n outputDeps(name, pkg.latestVersion, deps, args.json);\n return;\n }\n\n const deps = await reg.fetchDependencies(name, version);\n outputDeps(name, version, deps, args.json);\n });\n },\n});\n\nimport type { Dependency } from \"../core/types.ts\";\n\nfunction outputDeps(name: string, version: string, deps: Dependency[], json: boolean): void {\n if (json) {\n console.log(JSON.stringify(deps, null, 2));\n return;\n }\n\n consola.log(\"\");\n consola.log(\n ` \\x1b[1m${name}@${version}\\x1b[0m — ${deps.length} dependenc${deps.length === 1 ? \"y\" : \"ies\"}`,\n );\n consola.log(\"\");\n\n const byScope = new Map<string, Dependency[]>();\n for (const dep of deps) {\n const scope = dep.scope || \"runtime\";\n if (!byScope.has(scope)) byScope.set(scope, []);\n byScope.get(scope)!.push(dep);\n }\n\n const scopeColors: Record<string, string> = {\n runtime: \"\\x1b[32m\",\n development: \"\\x1b[33m\",\n build: \"\\x1b[35m\",\n test: \"\\x1b[36m\",\n optional: \"\\x1b[90m\",\n };\n\n for (const [scope, scopeDeps] of byScope) {\n const color = scopeColors[scope] ?? \"\\x1b[0m\";\n consola.log(` ${color}${scope}\\x1b[0m (${scopeDeps.length})`);\n for (const dep of scopeDeps) {\n const opt = dep.optional ? \" \\x1b[90m(optional)\\x1b[0m\" : \"\";\n consola.log(` ${dep.name} \\x1b[90m${dep.requirements}\\x1b[0m${opt}`);\n }\n consola.log(\"\");\n }\n}\n"],"mappings":";;;;;;AAIA,IAAA,eAAe,cAAc;CAC3B,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;EACJ,GAAG;EACH,MAAM;GACJ,MAAM;GACN,aAAa;GACb,UAAU;;EAEb;CACD,MAAM,IAAI,EAAE,QAAQ;AAClB,QAAM,kBAAkB,YAAY;GAClC,MAAM,CAAC,KAAK,MAAM,WAAW,YAAY,KAAK,MAAM,CAAC,KAAK,YAAY;AAEtE,OAAI,CAAC,SAAS;IAEZ,MAAM,MAAM,MAAM,IAAI,aAAa,KAAK;AACxC,QAAI,CAAC,IAAI,eAAe;AACtB,aAAQ,MACN,kFACD;AACD,aAAQ,KAAK,kCAAkC;AAC/C,aAAQ,KAAK,EAAE;;AAEjB,YAAQ,KAAK,uCAAuC,IAAI,gBAAgB;IACxE,MAAM,OAAO,MAAM,IAAI,kBAAkB,MAAM,IAAI,cAAc;AACjE,eAAW,MAAM,IAAI,eAAe,MAAM,KAAK,KAAK;AACpD;;AAIF,cAAW,MAAM,SADJ,MAAM,IAAI,kBAAkB,MAAM,QAAQ,EACvB,KAAK,KAAK;IAC1C;;CAEL,CAAC;AAIF,SAAS,WAAW,MAAc,SAAiB,MAAoB,MAAqB;AAC1F,KAAI,MAAM;AACR,UAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;AAC1C;;AAGF,SAAQ,IAAI,GAAG;AACf,SAAQ,IACN,YAAY,KAAK,GAAG,QAAQ,YAAY,KAAK,OAAO,YAAY,KAAK,WAAW,IAAI,MAAM,QAC3F;AACD,SAAQ,IAAI,GAAG;CAEf,MAAM,0BAAU,IAAI,KAA2B;AAC/C,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,QAAQ,IAAI,SAAS;AAC3B,MAAI,CAAC,QAAQ,IAAI,MAAM,CAAE,SAAQ,IAAI,OAAO,EAAE,CAAC;AAC/C,UAAQ,IAAI,MAAM,CAAE,KAAK,IAAI;;CAG/B,MAAM,cAAsC;EAC1C,SAAS;EACT,aAAa;EACb,OAAO;EACP,MAAM;EACN,UAAU;EACX;AAED,MAAK,MAAM,CAAC,OAAO,cAAc,SAAS;EACxC,MAAM,QAAQ,YAAY,UAAU;AACpC,UAAQ,IAAI,KAAK,QAAQ,MAAM,WAAW,UAAU,OAAO,GAAG;AAC9D,OAAK,MAAM,OAAO,WAAW;GAC3B,MAAM,MAAM,IAAI,WAAW,+BAA+B;AAC1D,WAAQ,IAAI,OAAO,IAAI,KAAK,WAAW,IAAI,aAAa,SAAS,MAAM;;AAEzE,UAAQ,IAAI,GAAG"}
@@ -1,26 +0,0 @@
1
- import { i as Package } from "../_chunks/types.mjs";
2
- import { t as Registry } from "../_chunks/registry.mjs";
3
- import * as citty from "citty";
4
-
5
- //#region src/commands/info.d.ts
6
- declare function outputPackageInfo(pkg: Package, name: string, reg: Registry): void;
7
- declare const _default: citty.CommandDef<{
8
- readonly purl: {
9
- readonly type: "positional";
10
- readonly description: "Package PURL (e.g. pkg:npm/lodash, cargo/serde@1.0)";
11
- readonly required: true;
12
- };
13
- readonly json: {
14
- readonly type: "boolean";
15
- readonly description: "Output as JSON";
16
- readonly default: false;
17
- };
18
- readonly "no-cache": {
19
- readonly type: "boolean";
20
- readonly description: "Bypass cache, fetch fresh data";
21
- readonly default: false;
22
- };
23
- }>;
24
- //#endregion
25
- export { _default as default, outputPackageInfo };
26
- //# sourceMappingURL=info.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"info.d.mts","names":[],"sources":["../../src/commands/info.ts"],"mappings":";;;;;iBAOgB,iBAAA,CAAkB,GAAA,EAAK,OAAA,EAAS,IAAA,UAAc,GAAA,EAAK,QAAA;AAAA,cA8BlE,QAAA"}
@@ -1,54 +0,0 @@
1
- import "../_chunks/registry.mjs";
2
- import "../_chunks/purl.mjs";
3
- import "../_chunks/registries.mjs";
4
- import { o as resolveDocsUrl } from "../_chunks/helpers.mjs";
5
- import { resolvePURL, sharedArgs, withErrorHandling } from "./shared.mjs";
6
- import { defineCommand } from "citty";
7
- import consola from "consola";
8
- function outputPackageInfo(pkg, name, reg) {
9
- const urls = reg.urls();
10
- const registryUrl = urls.registry(name);
11
- const docsUrl = resolveDocsUrl(pkg, urls, pkg.latestVersion || void 0);
12
- const showDocs = Boolean(docsUrl) && docsUrl !== pkg.homepage && docsUrl !== pkg.repository && docsUrl !== registryUrl;
13
- consola.log("");
14
- consola.log(` \x1b[1m\x1b[36m${pkg.name}\x1b[0m${pkg.latestVersion ? `\x1b[90m@${pkg.latestVersion}\x1b[0m` : ""}`);
15
- if (pkg.description) consola.log(` ${pkg.description}`);
16
- consola.log("");
17
- if (pkg.licenses) consola.log(` \x1b[90mLicense:\x1b[0m ${pkg.licenses}`);
18
- if (pkg.repository) consola.log(` \x1b[90mRepository:\x1b[0m ${pkg.repository}`);
19
- if (pkg.homepage) consola.log(` \x1b[90mHomepage:\x1b[0m ${pkg.homepage}`);
20
- if (showDocs) consola.log(` \x1b[90mDocs:\x1b[0m ${docsUrl}`);
21
- consola.log(` \x1b[90mRegistry:\x1b[0m ${registryUrl}`);
22
- if (pkg.keywords.length > 0) consola.log(` \x1b[90mKeywords:\x1b[0m ${pkg.keywords.join(", ")}`);
23
- if (pkg.namespace) consola.log(` \x1b[90mNamespace:\x1b[0m ${pkg.namespace}`);
24
- consola.log(` \x1b[90mEcosystem:\x1b[0m ${reg.ecosystem()}`);
25
- consola.log("");
26
- }
27
- var info_default = defineCommand({
28
- meta: {
29
- name: "info",
30
- description: "Show package metadata"
31
- },
32
- args: {
33
- ...sharedArgs,
34
- purl: {
35
- type: "positional",
36
- description: "Package PURL (e.g. pkg:npm/lodash, cargo/serde@1.0)",
37
- required: true
38
- }
39
- },
40
- async run({ args }) {
41
- await withErrorHandling(async () => {
42
- const [reg, name] = resolvePURL(args.purl, !args["no-cache"]);
43
- const pkg = await reg.fetchPackage(name);
44
- if (args.json) {
45
- console.log(JSON.stringify(pkg, null, 2));
46
- return;
47
- }
48
- outputPackageInfo(pkg, name, reg);
49
- });
50
- }
51
- });
52
- export { info_default as default, outputPackageInfo };
53
-
54
- //# sourceMappingURL=info.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"info.mjs","names":[],"sources":["../../src/commands/info.ts"],"sourcesContent":["import type { Package } from \"../core/types.ts\";\nimport type { Registry } from \"../core/registry.ts\";\nimport { defineCommand } from \"citty\";\nimport consola from \"consola\";\nimport { resolveDocsUrl } from \"../helpers.ts\";\nimport { sharedArgs, resolvePURL, withErrorHandling } from \"./shared.ts\";\n\nexport function outputPackageInfo(pkg: Package, name: string, reg: Registry): void {\n const urls = reg.urls();\n const registryUrl = urls.registry(name);\n const docsUrl = resolveDocsUrl(pkg, urls, pkg.latestVersion || undefined);\n const showDocs =\n Boolean(docsUrl) &&\n docsUrl !== pkg.homepage &&\n docsUrl !== pkg.repository &&\n docsUrl !== registryUrl;\n\n consola.log(\"\");\n consola.log(\n ` \\x1b[1m\\x1b[36m${pkg.name}\\x1b[0m${pkg.latestVersion ? `\\x1b[90m@${pkg.latestVersion}\\x1b[0m` : \"\"}`,\n );\n if (pkg.description) {\n consola.log(` ${pkg.description}`);\n }\n consola.log(\"\");\n\n if (pkg.licenses) consola.log(` \\x1b[90mLicense:\\x1b[0m ${pkg.licenses}`);\n if (pkg.repository) consola.log(` \\x1b[90mRepository:\\x1b[0m ${pkg.repository}`);\n if (pkg.homepage) consola.log(` \\x1b[90mHomepage:\\x1b[0m ${pkg.homepage}`);\n if (showDocs) consola.log(` \\x1b[90mDocs:\\x1b[0m ${docsUrl}`);\n consola.log(` \\x1b[90mRegistry:\\x1b[0m ${registryUrl}`);\n if (pkg.keywords.length > 0) {\n consola.log(` \\x1b[90mKeywords:\\x1b[0m ${pkg.keywords.join(\", \")}`);\n }\n if (pkg.namespace) consola.log(` \\x1b[90mNamespace:\\x1b[0m ${pkg.namespace}`);\n consola.log(` \\x1b[90mEcosystem:\\x1b[0m ${reg.ecosystem()}`);\n consola.log(\"\");\n}\n\nexport default defineCommand({\n meta: {\n name: \"info\",\n description: \"Show package metadata\",\n },\n args: {\n ...sharedArgs,\n purl: {\n type: \"positional\",\n description: \"Package PURL (e.g. pkg:npm/lodash, cargo/serde@1.0)\",\n required: true,\n },\n },\n async run({ args }) {\n await withErrorHandling(async () => {\n const [reg, name] = resolvePURL(args.purl, !args[\"no-cache\"]);\n const pkg = await reg.fetchPackage(name);\n\n if (args.json) {\n console.log(JSON.stringify(pkg, null, 2));\n return;\n }\n\n outputPackageInfo(pkg, name, reg);\n });\n },\n});\n"],"mappings":";;;;;;;AAOA,SAAgB,kBAAkB,KAAc,MAAc,KAAqB;CACjF,MAAM,OAAO,IAAI,MAAM;CACvB,MAAM,cAAc,KAAK,SAAS,KAAK;CACvC,MAAM,UAAU,eAAe,KAAK,MAAM,IAAI,iBAAiB,KAAA,EAAU;CACzE,MAAM,WACJ,QAAQ,QAAQ,IAChB,YAAY,IAAI,YAChB,YAAY,IAAI,cAChB,YAAY;AAEd,SAAQ,IAAI,GAAG;AACf,SAAQ,IACN,oBAAoB,IAAI,KAAK,SAAS,IAAI,gBAAgB,YAAY,IAAI,cAAc,WAAW,KACpG;AACD,KAAI,IAAI,YACN,SAAQ,IAAI,KAAK,IAAI,cAAc;AAErC,SAAQ,IAAI,GAAG;AAEf,KAAI,IAAI,SAAU,SAAQ,IAAI,gCAAgC,IAAI,WAAW;AAC7E,KAAI,IAAI,WAAY,SAAQ,IAAI,gCAAgC,IAAI,aAAa;AACjF,KAAI,IAAI,SAAU,SAAQ,IAAI,gCAAgC,IAAI,WAAW;AAC7E,KAAI,SAAU,SAAQ,IAAI,gCAAgC,UAAU;AACpE,SAAQ,IAAI,gCAAgC,cAAc;AAC1D,KAAI,IAAI,SAAS,SAAS,EACxB,SAAQ,IAAI,gCAAgC,IAAI,SAAS,KAAK,KAAK,GAAG;AAExE,KAAI,IAAI,UAAW,SAAQ,IAAI,gCAAgC,IAAI,YAAY;AAC/E,SAAQ,IAAI,gCAAgC,IAAI,WAAW,GAAG;AAC9D,SAAQ,IAAI,GAAG;;AAGjB,IAAA,eAAe,cAAc;CAC3B,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;EACJ,GAAG;EACH,MAAM;GACJ,MAAM;GACN,aAAa;GACb,UAAU;;EAEb;CACD,MAAM,IAAI,EAAE,QAAQ;AAClB,QAAM,kBAAkB,YAAY;GAClC,MAAM,CAAC,KAAK,QAAQ,YAAY,KAAK,MAAM,CAAC,KAAK,YAAY;GAC7D,MAAM,MAAM,MAAM,IAAI,aAAa,KAAK;AAExC,OAAI,KAAK,MAAM;AACb,YAAQ,IAAI,KAAK,UAAU,KAAK,MAAM,EAAE,CAAC;AACzC;;AAGF,qBAAkB,KAAK,MAAM,IAAI;IACjC;;CAEL,CAAC"}
@@ -1,23 +0,0 @@
1
- import * as citty from "citty";
2
-
3
- //#region src/commands/maintainers.d.ts
4
- declare const _default: citty.CommandDef<{
5
- readonly purl: {
6
- readonly type: "positional";
7
- readonly description: "Package PURL (e.g. pkg:npm/lodash, gem/rails)";
8
- readonly required: true;
9
- };
10
- readonly json: {
11
- readonly type: "boolean";
12
- readonly description: "Output as JSON";
13
- readonly default: false;
14
- };
15
- readonly "no-cache": {
16
- readonly type: "boolean";
17
- readonly description: "Bypass cache, fetch fresh data";
18
- readonly default: false;
19
- };
20
- }>;
21
- //#endregion
22
- export { _default as default };
23
- //# sourceMappingURL=maintainers.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"maintainers.d.mts","names":[],"sources":["../../src/commands/maintainers.ts"],"mappings":""}
@@ -1,46 +0,0 @@
1
- import "../_chunks/registry.mjs";
2
- import "../_chunks/purl.mjs";
3
- import "../_chunks/registries.mjs";
4
- import { resolvePURL, sharedArgs, withErrorHandling } from "./shared.mjs";
5
- import { defineCommand } from "citty";
6
- import consola from "consola";
7
- var maintainers_default = defineCommand({
8
- meta: {
9
- name: "maintainers",
10
- description: "List package maintainers"
11
- },
12
- args: {
13
- ...sharedArgs,
14
- purl: {
15
- type: "positional",
16
- description: "Package PURL (e.g. pkg:npm/lodash, gem/rails)",
17
- required: true
18
- }
19
- },
20
- async run({ args }) {
21
- await withErrorHandling(async () => {
22
- const [reg, name] = resolvePURL(args.purl, !args["no-cache"]);
23
- const maintainers = await reg.fetchMaintainers(name);
24
- if (args.json) {
25
- console.log(JSON.stringify(maintainers, null, 2));
26
- return;
27
- }
28
- consola.log("");
29
- consola.log(` \x1b[1m${name}\x1b[0m — ${maintainers.length} maintainer${maintainers.length === 1 ? "" : "s"}`);
30
- consola.log("");
31
- for (const m of maintainers) {
32
- const nameStr = m.name || m.login || "unknown";
33
- const parts = [nameStr];
34
- if (m.login && m.login !== nameStr) parts.push(`\x1b[90m(${m.login})\x1b[0m`);
35
- if (m.email) parts.push(`\x1b[90m<${m.email}>\x1b[0m`);
36
- if (m.role) parts.push(`\x1b[36m[${m.role}]\x1b[0m`);
37
- consola.log(` ${parts.join(" ")}`);
38
- if (m.url) consola.log(` \x1b[90m${m.url}\x1b[0m`);
39
- }
40
- consola.log("");
41
- });
42
- }
43
- });
44
- export { maintainers_default as default };
45
-
46
- //# sourceMappingURL=maintainers.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"maintainers.mjs","names":[],"sources":["../../src/commands/maintainers.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\nimport consola from \"consola\";\nimport { sharedArgs, resolvePURL, withErrorHandling } from \"./shared.ts\";\n\nexport default defineCommand({\n meta: {\n name: \"maintainers\",\n description: \"List package maintainers\",\n },\n args: {\n ...sharedArgs,\n purl: {\n type: \"positional\",\n description: \"Package PURL (e.g. pkg:npm/lodash, gem/rails)\",\n required: true,\n },\n },\n async run({ args }) {\n await withErrorHandling(async () => {\n const [reg, name] = resolvePURL(args.purl, !args[\"no-cache\"]);\n const maintainers = await reg.fetchMaintainers(name);\n\n if (args.json) {\n console.log(JSON.stringify(maintainers, null, 2));\n return;\n }\n\n consola.log(\"\");\n consola.log(\n ` \\x1b[1m${name}\\x1b[0m — ${maintainers.length} maintainer${maintainers.length === 1 ? \"\" : \"s\"}`,\n );\n consola.log(\"\");\n\n for (const m of maintainers) {\n const nameStr = m.name || m.login || \"unknown\";\n const parts: string[] = [nameStr];\n if (m.login && m.login !== nameStr) parts.push(`\\x1b[90m(${m.login})\\x1b[0m`);\n if (m.email) parts.push(`\\x1b[90m<${m.email}>\\x1b[0m`);\n if (m.role) parts.push(`\\x1b[36m[${m.role}]\\x1b[0m`);\n consola.log(` ${parts.join(\" \")}`);\n if (m.url) consola.log(` \\x1b[90m${m.url}\\x1b[0m`);\n }\n consola.log(\"\");\n });\n },\n});\n"],"mappings":";;;;;;AAIA,IAAA,sBAAe,cAAc;CAC3B,MAAM;EACJ,MAAM;EACN,aAAa;EACd;CACD,MAAM;EACJ,GAAG;EACH,MAAM;GACJ,MAAM;GACN,aAAa;GACb,UAAU;;EAEb;CACD,MAAM,IAAI,EAAE,QAAQ;AAClB,QAAM,kBAAkB,YAAY;GAClC,MAAM,CAAC,KAAK,QAAQ,YAAY,KAAK,MAAM,CAAC,KAAK,YAAY;GAC7D,MAAM,cAAc,MAAM,IAAI,iBAAiB,KAAK;AAEpD,OAAI,KAAK,MAAM;AACb,YAAQ,IAAI,KAAK,UAAU,aAAa,MAAM,EAAE,CAAC;AACjD;;AAGF,WAAQ,IAAI,GAAG;AACf,WAAQ,IACN,YAAY,KAAK,YAAY,YAAY,OAAO,aAAa,YAAY,WAAW,IAAI,KAAK,MAC9F;AACD,WAAQ,IAAI,GAAG;AAEf,QAAK,MAAM,KAAK,aAAa;IAC3B,MAAM,UAAU,EAAE,QAAQ,EAAE,SAAS;IACrC,MAAM,QAAkB,CAAC,QAAQ;AACjC,QAAI,EAAE,SAAS,EAAE,UAAU,QAAS,OAAM,KAAK,YAAY,EAAE,MAAM,UAAU;AAC7E,QAAI,EAAE,MAAO,OAAM,KAAK,YAAY,EAAE,MAAM,UAAU;AACtD,QAAI,EAAE,KAAM,OAAM,KAAK,YAAY,EAAE,KAAK,UAAU;AACpD,YAAQ,IAAI,KAAK,MAAM,KAAK,IAAI,GAAG;AACnC,QAAI,EAAE,IAAK,SAAQ,IAAI,eAAe,EAAE,IAAI,SAAS;;AAEvD,WAAQ,IAAI,GAAG;IACf;;CAEL,CAAC"}
@@ -1,27 +0,0 @@
1
- import "../_chunks/types.mjs";
2
- import { t as Registry } from "../_chunks/registry.mjs";
3
- import "../_chunks/index.mjs";
4
-
5
- //#region src/commands/shared.d.ts
6
- declare const sharedArgs: {
7
- readonly json: {
8
- readonly type: "boolean";
9
- readonly description: "Output as JSON";
10
- readonly default: false;
11
- };
12
- readonly "no-cache": {
13
- readonly type: "boolean";
14
- readonly description: "Bypass cache, fetch fresh data";
15
- readonly default: false;
16
- };
17
- };
18
- /**
19
- * Resolve a PURL string or shorthand into [registry, name, version].
20
- * Uses CachedRegistry unless --no-cache is set.
21
- */
22
- declare function resolvePURL(input: string, useCache?: boolean): [Registry, string, string];
23
- /** Run a command with standard error handling. */
24
- declare function withErrorHandling(fn: () => Promise<void>): Promise<void>;
25
- //#endregion
26
- export { resolvePURL, sharedArgs, withErrorHandling };
27
- //# sourceMappingURL=shared.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"shared.d.mts","names":[],"sources":["../../src/commands/shared.ts"],"mappings":";;;;;cAaa,UAAA;EAAA;;;;;;;;;;;;;;;iBAiBG,WAAA,CAAY,KAAA,UAAe,QAAA,cAAmB,QAAA;AAA9D;AAAA,iBAkBsB,iBAAA,CAAkB,EAAA,QAAU,OAAA,SAAgB,OAAA"}