{"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 type { ClientOptions, RateLimiter } from \"./types.ts\";\nimport { HTTPError, RateLimitError } from \"./errors.ts\";\nimport { version } from \"../version.ts\";\n\nconst DEFAULT_MAX_RETRIES = 5;\nconst DEFAULT_BASE_DELAY = 50;\nconst DEFAULT_TIMEOUT = 30_000;\nconst DEFAULT_USER_AGENT = `agntn-registries/${version} (+https://github.com/agntn/registries)`;\nconst MAX_TIMER_DELAY = 2_147_483_647;\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/** Statuses worth another go: timeouts, conflicts, rate limits and servers having a bad day. */\nconst RETRY_STATUS_CODES = new Set([408, 409, 425, 429, 500, 502, 503, 504]);\n\n/** Statuses whose response never carries a body. */\nconst EMPTY_STATUS_CODES = new Set([101, 204, 205, 304]);\n\n/** One finished attempt: the decoded body, or the error it ends on if nobody retries. */\ntype Attempt =\n  | { readonly ok: true; readonly data: unknown }\n  | {\n      readonly ok: false;\n      readonly error: Error;\n      readonly retryable: boolean;\n      readonly status?: number;\n      readonly retryAfter?: string | null;\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\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\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    for (let attempt = 0; ; attempt++) {\n      const outcome = await this.attempt(url, signal, headers);\n      if (outcome.ok) return outcome.data as T;\n      if (!this.canRetry(outcome, attempt, signal)) throw outcome.error;\n\n      await abortableDelay(this.retryDelay(attempt, url, outcome), signal);\n      if (signal?.aborted) throw new HTTPError(0, url, \"\");\n    }\n  }\n\n  /**\n   * One request under a fresh timeout. Failures come back as data, so the loop picks what's next.\n   *\n   * @param url - Request URL.\n   * @param signal - Optional cancellation signal.\n   * @param headers - Optional request headers.\n   * @returns {Promise<Attempt>} The decoded body or the failure.\n   */\n  private async attempt(\n    url: string,\n    signal?: AbortSignal,\n    headers?: Readonly<Record<string, string>>,\n  ): Promise<Attempt> {\n    const init = { headers: this.requestHeaders(headers), signal: this.attemptSignal(signal) };\n    let status: number;\n    let retryAfter: string | null;\n    let text: string | undefined;\n    try {\n      const response = await fetch(url, init);\n      ({ status } = response);\n      retryAfter = response.headers.get(\"Retry-After\");\n      text = EMPTY_STATUS_CODES.has(status) ? undefined : await response.text();\n    } catch {\n      return { ok: false, error: new HTTPError(0, url, \"\"), retryable: !signal?.aborted };\n    }\n\n    if (status < 400 || status >= 600) return { ok: true, data: parseBody(text) };\n\n    const error =\n      status === 429\n        ? new RateLimitError(parseRetryAfter(retryAfter))\n        : new HTTPError(status, url, text ?? \"\");\n    return { ok: false, error, retryable: RETRY_STATUS_CODES.has(status), status, retryAfter };\n  }\n\n  private canRetry(\n    failure: Readonly<{ retryable: boolean }>,\n    attempt: number,\n    signal?: AbortSignal,\n  ): boolean {\n    return failure.retryable && attempt < this.maxRetries && !signal?.aborted;\n  }\n\n  /**\n   * Exponential backoff with up to 10% jitter, stretched to a longer Retry-After.\n   *\n   * @param attempt - Zero-based index of the attempt that just failed.\n   * @param url - Request URL, for the error when Retry-After is unschedulable.\n   * @param failure - The failed attempt.\n   * @returns {number} Milliseconds to wait before the next attempt.\n   */\n  private retryDelay(\n    attempt: number,\n    url: string,\n    failure: Readonly<{ status?: number; retryAfter?: string | null }>,\n  ): number {\n    const delay = this.baseDelay * Math.pow(2, attempt - 1);\n    const jitteredDelay = delay + delay * Math.random() * 0.1;\n    try {\n      return retryDelayFor(failure.retryAfter, jitteredDelay);\n    } catch (error) {\n      if (error instanceof RateLimitError && failure.status !== 429) {\n        throw new HTTPError(failure.status ?? 0, url, \"\");\n      }\n      throw error;\n    }\n  }\n\n  /**\n   * Default headers, each replaced by a caller header of the same name in any letter case.\n   *\n   * @param overrides - Optional request headers.\n   * @returns {Headers} The headers for one request.\n   */\n  private requestHeaders(overrides?: Readonly<Record<string, string>>): Headers {\n    const headers = new Headers({ Accept: \"application/json\", \"User-Agent\": this.userAgent });\n    for (const [name, value] of Object.entries(overrides ?? {})) headers.set(name, value);\n    return headers;\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 * JSON when it parses, raw text when it doesn't, and no prototype keys smuggled in by a registry.\n *\n * @param text - Response body, or `undefined` for a bodiless status.\n * @returns {unknown} The decoded body.\n */\nfunction parseBody(text: string | undefined): unknown {\n  if (text === undefined) return undefined;\n  try {\n    return JSON.parse(text, (key, value: unknown) =>\n      key === \"__proto__\" ||\n      (key === \"constructor\" && typeof value === \"object\" && value !== null && \"prototype\" in value)\n        ? undefined\n        : value,\n    );\n  } catch {\n    return text;\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(\n    builtins.map((entry): [string, RegistryEntry] => [\n      entry.ecosystem,\n      { ...entry, load: shared(entry.load) },\n    ]),\n  );\n  return entries;\n}\n\n/**\n * One import for every caller: under jiti (Pi, OMP) an overlapping `import()` sees no exports.\n *\n * @param load - Loader to run on the first call and again after a failure.\n * @returns {() => Promise<T>} Loader answering every call from the same pending promise.\n */\nfunction shared<T>(load: () => Promise<T>): () => Promise<T> {\n  let pending: Promise<T> | undefined;\n  return () => {\n    pending ??= load().catch((error: unknown) => {\n      pending = undefined;\n      throw error;\n    });\n    return pending;\n  };\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; parallel callers\n * share that import and later calls reuse it. A failed import is retried on the next call.\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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"}