{"version":3,"file":"registry.mjs","names":[],"sources":["../../src/core/errors.ts","../../src/core/client.ts","../../src/core/registry.ts"],"sourcesContent":["/** Custom error types for registry operations. */\n\nexport class PkioError extends Error {\n  constructor(message: string, options?: ErrorOptions) {\n    super(message, options);\n    this.name = \"PkioError\";\n  }\n}\n\nexport class HTTPError extends PkioError {\n  readonly statusCode: number;\n  readonly url: string;\n  readonly body: string;\n\n  constructor(statusCode: number, url: string, body: string) {\n    super(`HTTP ${statusCode}: ${url}`);\n    this.name = \"HTTPError\";\n    this.statusCode = statusCode;\n    this.url = url;\n    this.body = body;\n  }\n\n  isNotFound(): boolean {\n    return this.statusCode === 404;\n  }\n\n  isRateLimit(): boolean {\n    return this.statusCode === 429;\n  }\n\n  isServerError(): boolean {\n    return this.statusCode >= 500;\n  }\n}\n\nexport class NotFoundError extends PkioError {\n  readonly ecosystem: string;\n  readonly packageName: string;\n  readonly version: string;\n\n  constructor(ecosystem: string, packageName: string, version = \"\") {\n    const versionSuffix = version ? `@${version}` : \"\";\n    super(`Package not found: ${ecosystem}/${packageName}${versionSuffix}`);\n    this.name = \"NotFoundError\";\n    this.ecosystem = ecosystem;\n    this.packageName = packageName;\n    this.version = version;\n  }\n}\n\nexport class RateLimitError extends PkioError {\n  readonly retryAfter: number;\n\n  constructor(retryAfter: number) {\n    super(`Rate limited. Retry after ${retryAfter}s`);\n    this.name = \"RateLimitError\";\n    this.retryAfter = retryAfter;\n  }\n}\n\nexport class UnknownEcosystemError extends PkioError {\n  readonly ecosystem: string;\n\n  constructor(ecosystem: string) {\n    super(`Unknown ecosystem: ${ecosystem}`);\n    this.name = \"UnknownEcosystemError\";\n    this.ecosystem = ecosystem;\n  }\n}\n\nexport class InvalidPURLError extends PkioError {\n  readonly purl: string;\n\n  constructor(purl: string, reason: string) {\n    super(`Invalid PURL \"${purl}\": ${reason}`);\n    this.name = \"InvalidPURLError\";\n    this.purl = purl;\n  }\n}\n\n/**\n * Rethrow a fetch failure as the core error an adapter owes its caller.\n *\n * A 404 from the registry becomes `NotFoundError` for the package; every other failure is the\n * `HTTPError` the client already threw.\n *\n * @param error - The value the client rejected with.\n * @param ecosystem - Ecosystem key of the adapter.\n * @param packageName - Package the request was about.\n * @param version - Version the request was about, when it had one.\n * @returns {never} Always throws.\n */\nexport function rethrowFetchError(\n  error: unknown,\n  ecosystem: string,\n  packageName: string,\n  version = \"\",\n): never {\n  if (error instanceof HTTPError && error.isNotFound()) {\n    throw new NotFoundError(ecosystem, packageName, version);\n  }\n  throw error;\n}\n","import { ofetch, FetchError } from \"ofetch\";\nimport type { $Fetch, FetchOptions } from \"ofetch\";\nimport type { ClientOptions, RateLimiter } from \"./types.ts\";\nimport { HTTPError, RateLimitError } from \"./errors.ts\";\n\nconst DEFAULT_MAX_RETRIES = 5;\nconst DEFAULT_BASE_DELAY = 50;\nconst DEFAULT_TIMEOUT = 30_000;\nconst DEFAULT_USER_AGENT = \"registries/0.1.0\";\nconst MAX_TIMER_DELAY = 2_147_483_647;\n\nfunction retryCount(value: unknown): number {\n  return typeof value === \"number\" ? value : 0;\n}\n\nfunction parseRetryAfterValue(header: string | null | undefined): number | undefined {\n  if (!header) return undefined;\n  const trimmed = header.trim();\n  if (!trimmed) return undefined;\n\n  if (/^\\d+$/.test(trimmed)) {\n    const seconds = Number(trimmed);\n    return Number.isNaN(seconds) ? undefined : seconds;\n  }\n\n  const timestamp = /[a-z]/i.test(trimmed) ? Date.parse(trimmed) : NaN;\n  if (Number.isNaN(timestamp)) return undefined;\n\n  const seconds = Math.ceil((timestamp - Date.now()) / 1000);\n  return Math.max(seconds, 0);\n}\n\n/**\n * Parse a Retry-After header into seconds, defaulting to 60.\n *\n * @param header - Numeric seconds or an HTTP date.\n * @returns {number} The retry delay in seconds.\n */\nexport function parseRetryAfter(header: string | null | undefined): number {\n  return parseRetryAfterValue(header) ?? 60;\n}\n\n/**\n * Apply a valid Retry-After value or reject an unschedulable delay.\n *\n * @param header - Numeric seconds or an HTTP date.\n * @param fallbackDelay - Delay in milliseconds used without a valid header.\n * @returns {number} A timer-safe delay in milliseconds.\n */\nexport function retryDelayFor(header: string | null | undefined, fallbackDelay: number): number {\n  const retryAfter = parseRetryAfterValue(header);\n  if (retryAfter === undefined) return fallbackDelay;\n\n  const retryAfterDelay = retryAfter * 1000;\n  if (!Number.isFinite(retryAfterDelay) || retryAfterDelay > MAX_TIMER_DELAY) {\n    throw new RateLimitError(retryAfter);\n  }\n  return Math.max(fallbackDelay, retryAfterDelay);\n}\n\n/** HTTP client with retry, backoff, rate limiting, and timeout. */\nexport class Client {\n  readonly maxRetries: number;\n  readonly baseDelay: number;\n  readonly timeout: number;\n  readonly userAgent: string;\n  private readonly rateLimiter: RateLimiter | null;\n  private readonly fetch: $Fetch;\n\n  constructor(options: ClientOptions = {}) {\n    this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;\n    this.baseDelay = options.baseDelay ?? DEFAULT_BASE_DELAY;\n    this.timeout = options.timeout ?? DEFAULT_TIMEOUT;\n    this.userAgent = options.userAgent ?? DEFAULT_USER_AGENT;\n    this.rateLimiter = options.rateLimiter ?? null;\n\n    this.fetch = ofetch.create({\n      retry: this.maxRetries,\n      retryStatusCodes: [408, 409, 425, 429, 500, 502, 503, 504],\n      headers: {\n        Accept: \"application/json\",\n        \"User-Agent\": this.userAgent,\n      },\n    });\n  }\n\n  /**\n   * Fetch JSON with retry and rate limiting.\n   *\n   * @param url - Request URL.\n   * @param signal - Optional cancellation signal.\n   * @param headers - Optional request headers.\n   * @returns {Promise<T>} The decoded response body.\n   */\n  async getJSON<T>(\n    url: string,\n    signal?: AbortSignal,\n    headers?: Readonly<Record<string, string>>,\n  ): Promise<T> {\n    if (this.rateLimiter) {\n      await this.rateLimiter.wait(signal);\n    }\n\n    try {\n      return await this.fetch<T>(url, { headers, ...this.retryControl(signal) });\n    } catch (error) {\n      if (error instanceof FetchError) {\n        if (error.statusCode === 429) {\n          throw new RateLimitError(parseRetryAfter(error.response?.headers.get(\"Retry-After\")));\n        }\n\n        const body = typeof error.data === \"string\" ? error.data : JSON.stringify(error.data ?? \"\");\n\n        throw new HTTPError(error.statusCode ?? 0, url, body);\n      }\n      throw error;\n    }\n  }\n\n  /**\n   * ofetch drops its timeout once a signal is supplied, sleeps through backoff with a plain\n   * timer and retries after an abort, so the request owns all three here.\n   *\n   * @param signal - Optional cancellation signal.\n   * @returns {FetchOptions} The request hooks that own timeout, backoff and cancellation.\n   */\n  private retryControl(\n    signal?: AbortSignal,\n  ): Pick<FetchOptions, \"signal\" | \"retryDelay\" | \"onRequest\" | \"onRequestError\"> {\n    let pendingDelay = 0;\n    return {\n      signal,\n      retryDelay: (context) => {\n        const remaining = retryCount(context.options.retry);\n        const attempt = this.maxRetries - remaining;\n        const delay = this.baseDelay * Math.pow(2, attempt - 1);\n        const jitteredDelay = delay + delay * Math.random() * 0.1;\n        const retryAfter = context.response?.headers.get(\"Retry-After\");\n        try {\n          pendingDelay = retryDelayFor(retryAfter, jitteredDelay);\n        } catch (error) {\n          if (error instanceof RateLimitError && context.response?.status !== 429) {\n            const requestURL =\n              typeof context.request === \"string\" ? context.request : context.request.url;\n            throw new HTTPError(context.response?.status ?? 0, requestURL, \"\");\n          }\n          throw error;\n        }\n        return 0;\n      },\n      onRequest: async ({ options }) => {\n        if (pendingDelay > 0) {\n          await abortableDelay(pendingDelay, signal);\n          pendingDelay = 0;\n        }\n        options.signal = this.attemptSignal(signal);\n      },\n      onRequestError: ({ options }) => {\n        if (signal?.aborted) options.retry = false;\n      },\n    };\n  }\n\n  private attemptSignal(signal?: AbortSignal): AbortSignal | undefined {\n    const signals = [signal, this.timeout > 0 ? AbortSignal.timeout(this.timeout) : undefined];\n    const active = signals.filter((candidate) => candidate !== undefined);\n    return active.length > 0 ? AbortSignal.any(active) : undefined;\n  }\n}\n\n/**\n * Sleep that returns as soon as the signal fires, so an abort never waits out a Retry-After.\n *\n * @param milliseconds - Delay before resolving.\n * @param signal - Optional cancellation signal that ends the wait early.\n * @returns {Promise<void>} Resolution after the delay or the abort.\n */\nfunction abortableDelay(milliseconds: number, signal?: AbortSignal): Promise<void> {\n  if (!signal) return new Promise((resolve) => setTimeout(resolve, milliseconds));\n  if (signal.aborted) return Promise.resolve();\n  return new Promise((resolve) => {\n    const onAbort = (): void => {\n      clearTimeout(timer);\n      resolve();\n    };\n    const timer = setTimeout(() => {\n      signal.removeEventListener(\"abort\", onAbort);\n      resolve();\n    }, milliseconds);\n    signal.addEventListener(\"abort\", onAbort, { once: true });\n  });\n}\n\nlet _defaultClient: Client | undefined;\n\n/**\n * Get or create the shared HTTP client.\n *\n * @returns {Client} The shared client.\n */\nexport function defaultClient(): Client {\n  _defaultClient ??= new Client();\n  return _defaultClient;\n}\n","import type { Client } from \"./client.ts\";\nimport { defaultClient } from \"./client.ts\";\nimport { UnknownEcosystemError } from \"./errors.ts\";\nimport { builtins } from \"../registries/index.ts\";\nimport type { Dependency, Maintainer, Package, URLBuilder, Version } from \"./types.ts\";\n\n/** Common base for package registries and registry decorators. */\nexport abstract class Registry {\n  abstract ecosystem(): string;\n  abstract fetchPackage(name: string, signal?: AbortSignal): Promise<Package>;\n  abstract fetchVersions(name: string, signal?: AbortSignal): Promise<Version[]>;\n  abstract fetchDependencies(\n    name: string,\n    version: string,\n    signal?: AbortSignal,\n  ): Promise<Dependency[]>;\n  abstract fetchMaintainers(name: string, signal?: AbortSignal): Promise<Maintainer[]>;\n  abstract urls(): URLBuilder;\n}\n\n/** Constructor every adapter exposes, built-in or registered from outside the package. */\nexport type RegistryConstructor = new (baseURL: string, client: Client) => Registry;\n\n/** One ecosystem the registry knows: static metadata plus a loader for the adapter class. */\nexport interface RegistryEntry {\n  /** PURL type the adapter serves. */\n  readonly ecosystem: string;\n  /** Registry API URL used when `create()` gets none. */\n  readonly defaultURL: string;\n  /** Resolves the adapter class; for a built-in that is a literal `import()` of its module. */\n  readonly load: () => Promise<RegistryConstructor>;\n}\n\nlet entries: Map<string, RegistryEntry> | undefined;\n\n/**\n * The registry table, seeded from the built-in manifest on first use.\n *\n * Seeding on first use rather than at module scope keeps this module free of calls a bundler\n * would have to keep, so a consumer that never resolves an ecosystem drops the table too.\n *\n * @returns {Map<string, RegistryEntry>} The seeded table.\n */\nfunction table(): Map<string, RegistryEntry> {\n  entries ??= new Map(builtins.map((entry): [string, RegistryEntry] => [entry.ecosystem, entry]));\n  return entries;\n}\n\n/**\n * Register an ecosystem adapter.\n *\n * Built-in adapters are already listed; this is the entry point for classes living outside the\n * package. Registering a key again replaces the previous adapter.\n *\n * @param ecosystem - Ecosystem key.\n * @param defaultURL - Default registry API URL.\n * @param RegistryClass - Adapter constructor.\n */\nexport function register(\n  ecosystem: string,\n  defaultURL: string,\n  RegistryClass: RegistryConstructor,\n): void {\n  table().set(ecosystem, { ecosystem, defaultURL, load: () => Promise.resolve(RegistryClass) });\n}\n\n/**\n * Create an adapter for a registered ecosystem.\n *\n * A built-in adapter's module is imported here, on the first call for its key; the module map\n * shares one import between parallel callers and answers later calls from cache.\n *\n * @param ecosystem - Ecosystem key.\n * @param baseURL - Optional registry API URL override.\n * @param client - Optional HTTP client.\n * @returns {Promise<Registry>} The registry adapter.\n * @throws {UnknownEcosystemError} When nothing is registered under `ecosystem`.\n */\nexport async function create(\n  ecosystem: string,\n  baseURL?: string,\n  client?: Client,\n): Promise<Registry> {\n  const entry = table().get(ecosystem);\n  if (!entry) {\n    throw new UnknownEcosystemError(ecosystem);\n  }\n  const RegistryClass = await entry.load();\n  return new RegistryClass(baseURL || entry.defaultURL, client ?? defaultClient());\n}\n\n/**\n * List registered ecosystems.\n *\n * @returns {string[]} The ecosystem keys, built-ins first in manifest order.\n */\nexport function ecosystems(): string[] {\n  return [...table().keys()];\n}\n\n/**\n * Check whether an ecosystem is registered.\n *\n * @param ecosystem - Ecosystem key.\n * @returns {boolean} Whether an adapter is registered.\n */\nexport function has(ecosystem: string): boolean {\n  return table().has(ecosystem);\n}\n"],"mappings":"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"}