/** * Phase 4b — registry client wrapper specific to the lockfile flow. * * This module enforces the "registry rule" defined in the plan: * `lock.registry` is canonical at runtime; `CURSELL_API_URL` is * consulted only when no lockfile exists yet (bootstrap). If the * env var is set AND differs from `lock.registry`, the command * errors out with a clear message before any network call. * * Responses are validated against a strict shape that includes * `contentHash`, `publishedBy`, and `publishedAt` (Phase 2B's * NOT NULL prerequisite). Missing fields raise * `RegistryResponseError`, which surfaces the registry as the * fault rather than letting it fall through to a confusing * lockfile-side validation error. */ import { z } from "zod"; import { HubApiClient } from "../shared/api-client.js"; import type { ContentHash } from "./schema.js"; declare const RegistryAgentSchema: z.ZodObject<{ slug: z.ZodString; canonicalRef: z.ZodNullable; canonicalUrl: z.ZodNullable; authorUsername: z.ZodOptional>; name: z.ZodString; description: z.ZodString; category: z.ZodString; currentVersion: z.ZodString; sizeWords: z.ZodNumber; sizeTag: z.ZodEnum<["lightweight", "medium", "large"]>; content: z.ZodString; contentHash: z.ZodObject<{ algo: z.ZodLiteral<"sha256-v1">; value: z.ZodString; }, "strip", z.ZodTypeAny, { algo: "sha256-v1"; value: string; }, { algo: "sha256-v1"; value: string; }>; publishedBy: z.ZodString; publishedAt: z.ZodString; }, "strip", z.ZodTypeAny, { contentHash: { algo: "sha256-v1"; value: string; }; publishedBy: string; publishedAt: string; category: string; slug: string; canonicalRef: string | null; canonicalUrl: string | null; name: string; description: string; currentVersion: string; sizeWords: number; sizeTag: "lightweight" | "medium" | "large"; content: string; authorUsername?: string | null | undefined; }, { contentHash: { algo: "sha256-v1"; value: string; }; publishedBy: string; publishedAt: string; category: string; slug: string; canonicalRef: string | null; canonicalUrl: string | null; name: string; description: string; currentVersion: string; sizeWords: number; sizeTag: "lightweight" | "medium" | "large"; content: string; authorUsername?: string | null | undefined; }>; export type RegistryAgent = z.infer; export declare class RegistryResponseError extends Error { readonly slug: string; constructor(slug: string, reason: string); } export declare class RegistryRuleError extends Error { constructor(lockRegistry: string, envRegistry: string); } /** * Resolve the effective registry URL. * * - If `lockRegistry` is non-null: it wins. If `envRegistry` is set * AND differs (after origin normalization), throw * `RegistryRuleError` (no silent override). * - If `lockRegistry` is null (bootstrap, no lockfile yet): use * `envRegistry` if set, else the default. * * URL equality is compared by `new URL().origin` so a trailing slash * or scheme/host casing difference doesn't trigger a spurious * conflict. Both inputs are constrained to http(s) by the lockfile * schema; non-parseable env values fall through to the raw string * compare and surface the error. */ export declare function resolveEffectiveRegistry(args: { lockRegistry: string | null; envRegistry: string | null | undefined; defaultRegistry: string; }): string; /** * Fetch the canonical agent payload for a slug + optional version. * If `version` is omitted, the registry returns the current * version. Response is shape-validated against * `RegistryAgentSchema` — missing/malformed fields raise * `RegistryResponseError`. */ export declare function fetchAgent(client: HubApiClient, ref: string, version?: string): Promise; /** Re-export for the consumers' convenience. */ export type { ContentHash };