/**
 * V2 Dependency Resolver — Phase 3 (Round 1)
 *
 * 4-step lookup chain for `import[].from` references:
 *   1. Local component in same spec
 *   2. Local npm package (node_modules/<name>/package.json)
 *   3. Registry library (Library.type: component) — HTTP stubbed for Round 1
 *   4. Registry factory (Library.type: factory) — HTTP stubbed for Round 1
 *
 * Decision points applied:
 *   D1: version defaults to ^latest (per-realize-run cache)
 *   Offline mode: skips steps 3 + 4, fails loudly if unresolvable
 *   Cache: <cacheDir>/registry-cache/ (default .specverse/registry-cache/)
 *   Fail-loud: throws DependencyResolutionError when nothing resolves
 *
 * @see docs/proposals/2026-05-08-COMPONENT-DEPENDENCIES-V2.md — "Realize bridge — Resolver"
 */
import type { SpecVerseAST, ComponentSpec } from '@specverse/types';
/**
 * A spec that has been resolved from a `from:` reference.
 * For Round 1 registry paths, `spec` is a minimal stub generated from
 * the registry Library record.
 */
export interface ResolvedComponent {
    /** The original `from:` value from the import entry that produced this. */
    fromName: string;
    /** Which step of the 4-step chain produced this result. */
    source: 'local' | 'npm' | 'registry-component' | 'registry-factory';
    /**
     * The resolved SpecVerse spec.  For local + npm sources this is the full
     * parsed spec.  For registry sources (stubs in Round 1) this is a minimal
     * object bearing at least the component's `name` and `version`.
     */
    spec: PartialSpec;
    /**
     * The resolved provider name (component name for local, npm package name
     * for npm, registry library/factory name for registry-*).
     */
    resolvedName: string;
    /**
     * Pinned version after ^latest expansion (or the version from the local
     * spec / npm package.json). Optional because some local components may
     * not declare a version field.
     */
    resolvedVersion?: string;
    /**
     * For source = 'npm' or 'registry-*': the package specifier to use in
     * generated `import` statements (e.g. '@stripe/stripe-js' or 'profit-calc').
     * For source = 'local': not populated; callers compute relative paths
     * from outputDir + resolvedName.
     */
    packageSpecifier?: string;
    /**
     * For source = 'local': relative path from the consumer's outputDir to
     * the provider's emitted module. Optional — when absent, callers fall
     * back to `../{resolvedName}` or similar convention.
     */
    localRelativePath?: string;
    /**
     * Registry coordinates when source is 'registry-component' or 'registry-factory'.
     */
    registryRef?: {
        name: string;
        version: string;
    };
    /**
     * For source = 'registry-component': the raw `.specly` content fetched from
     * the registry, when available. Parsing it into a full spec is downstream
     * work (the realize emitter); the resolver just threads it through.
     */
    specContent?: string;
}
/**
 * A factory reference returned when the registry resolves a capability match
 * (step 4).
 */
export interface FactoryReference {
    name: string;
    version: string;
    /** Factory metadata from registry — partial in Round 1 (HTTP is stubbed). */
    metadata?: Record<string, unknown>;
}
/**
 * Options passed to each `resolve()` call.  The full spec + workspace context
 * allow the local-component and npm-package steps to work without extra
 * configuration.
 */
export interface ResolveOptions {
    /** The spec being realized — used for local-component lookup (step 1). */
    spec: SpecVerseAST;
    /**
     * Absolute path to the workspace root.  Used to locate node_modules for
     * step 2.  Defaults to `process.cwd()`.
     */
    workspaceRoot?: string;
    /**
     * When true, steps 3 and 4 (registry) are skipped.  If a `from:` reference
     * cannot be resolved via steps 1–2, throws `DependencyResolutionError`.
     */
    offline?: boolean;
    /**
     * Directory where registry responses are cached.
     * Defaults to `.specverse/registry-cache/` inside `workspaceRoot`.
     */
    cacheDir?: string;
    /**
     * When true, treats the registry cache as stale and re-fetches even if a
     * cached entry exists.  Equivalent to the `--refresh-registry` flag.
     * Can also be set via the `SPECVERSE_REFRESH_REGISTRY=1` environment variable.
     */
    refreshRegistry?: boolean;
}
export interface DependencyResolver {
    /**
     * Resolve a `from:` reference to a component spec.
     *
     * Steps (in order):
     *   1. Local component in spec.components
     *   2. node_modules/<from>/package.json
     *   3. GET /api/libraries/<from> (Registry, Library.type: component) — STUBBED
     *   4. GET /api/libraries?type=factory&capability=<from> — STUBBED
     *
     * @param from    The `from:` value from the import entry.
     * @param version Semver range or pin.  Defaults to `^latest` (D1).
     * @param options Resolve-time context.
     * @returns ResolvedComponent or null when offline + not locally found.
     * @throws DependencyResolutionError when nothing resolves (not offline) or
     *         when offline and no local resolution is possible.
     */
    resolve(from: string, version?: string, options?: ResolveOptions): Promise<ResolvedComponent | null>;
    /**
     * Resolve a capability tag to a factory reference.
     * Used by realize emitters that need to find which factory covers a given
     * capability string.
     *
     * Delegates to step 4 of the chain.
     *
     * @throws DependencyResolutionError when no factory matches and not offline.
     */
    resolveCapability(capability: string, options?: ResolveOptions): Promise<FactoryReference | null>;
}
export declare class DependencyResolutionError extends Error {
    readonly from: string;
    readonly triedSteps: string[];
    constructor(message: string, from: string, triedSteps: string[]);
}
/** Minimal spec shape accepted from all resolution sources. */
export interface PartialSpec {
    name?: string;
    version?: string;
    components?: ComponentSpec[];
    [key: string]: unknown;
}
/**
 * The two registry lookups the resolver needs, decoupled from the HTTP client
 * so callers (and tests) can inject a fake.  The default implementation
 * (`RegistryClientGateway`) is backed by the real `RegistryClient`.
 *
 * Both methods treat "not found" AND transient network failure as a miss
 * (return null), so the resolver's 4-step fall-through and its own loud
 * `DependencyResolutionError` stay in control. Network failures are logged.
 */
export interface RegistryGateway {
    /**
     * Resolve a published component library to its `.specly` content.
     * @param name    The consumer's `from:` value (the library's canonical name).
     * @param version Semver range or pin; `^latest`/ranges collapse to `latest`.
     * @returns `{ name, version, specContent }` or null when absent.
     */
    getComponentLibrary(name: string, version: string): Promise<{
        name: string;
        version: string;
        specContent?: string;
    } | null>;
    /**
     * Find a factory advertising a capability (registry `Library.type: factory`).
     * @returns the best match or null when none advertise the capability.
     */
    findFactoryByCapability(capability: string): Promise<{
        name: string;
        version: string;
        metadata?: Record<string, unknown>;
    } | null>;
}
/**
 * Create a `DependencyResolver` instance.
 *
 * The resolver is stateless between realize runs.  A new instance should be
 * created per-run (or per test) to avoid cross-run cache pollution in memory.
 * On-disk cache in `<cacheDir>/registry-cache/` persists across runs and is
 * shared across instances that use the same directory.
 */
export declare function createDependencyResolver(deps?: {
    registry?: RegistryGateway;
}): DependencyResolver;
//# sourceMappingURL=index.d.ts.map