import { extractPromptUrls } from './sourceContext';
import type { DesignContextEntry, SourceContextInput } from './contracts';
import { ageBucketFor, confidenceBucketFor, type DesignContextStore, type FreshnessState } from './designContextStore';
/**
 * Validation, fetch, signal extraction, and markdown generation for
 * inspiration-link design context. Used only by the MCP
 * `create_zero_to_one_project` flow today. Standalone helpers stay
 * non-exposed to product surfaces; they exist so internal debugging and
 * unit tests can drive each stage in isolation.
 */
export interface InspirationFetchSuccess {
    ok: true;
    url: string;
    finalUrl: string;
    html: string;
    contentType: string;
    byteLength: number;
}
export interface InspirationFetchFailure {
    ok: false;
    url: string;
    reason: string;
}
export type InspirationFetchResult = InspirationFetchSuccess | InspirationFetchFailure;
export type InspirationFetcher = (url: string) => Promise<InspirationFetchResult>;
export interface LinkedCssFetchSuccess {
    ok: true;
    /** Originally requested stylesheet URL (post HTML resolution). */
    url: string;
    /** Final URL after redirects, normalized. */
    finalUrl: string;
    css: string;
    byteLength: number;
}
export interface LinkedCssFetchFailure {
    ok: false;
    url: string;
    reason: string;
}
export type LinkedCssFetchResult = LinkedCssFetchSuccess | LinkedCssFetchFailure;
export type LinkedCssFetcher = (url: string) => Promise<LinkedCssFetchResult>;
export type LinkIntent = 'inspiration' | 'reference' | 'unrelated';
export interface InspirationLink {
    url: string;
    intent: LinkIntent;
    /** Optional human label sourced from sourceArtifact entries when available. */
    label?: string;
}
export interface InspirationLinkClassification {
    inspiration: InspirationLink[];
    reference: InspirationLink[];
    /**
     * Whether multiple inspiration links should produce a single merged design
     * context or remain as separate per-slot guidance. Set by user-intent
     * heuristics on the prompt and explicit `sourceContext` roles.
     */
    mergeStrategy: 'merge' | 'separate';
}
/**
 * Single typography token (per DESIGN.md token-group shape). All fields
 * stay optional because static extraction may surface only some metrics
 * (a fontFamily without an explicit lineHeight is still useful).
 */
export interface TypographyToken {
    fontFamily?: string;
    fontSize?: string;
    fontWeight?: string;
    lineHeight?: string;
    letterSpacing?: string;
    fontVariationSettings?: string;
}
/**
 * Normalized `@font-face` evidence extracted from static CSS.
 * Keeps only reusable typography metadata and source hostnames,
 * never raw CSS declarations.
 */
export interface FontFaceEvidence {
    fontFamily: string;
    fontWeight?: string;
    fontStyle?: string;
    fontDisplay?: string;
    srcHosts: string[];
}
/**
 * Semantic color roles inferred from CSS rule context (body/.btn-primary/
 * .card/etc.) plus palette fallback. Keys are intentionally kebab-style
 * to match downstream DESIGN.md token group shape.
 */
export interface ColorRoles {
    primary?: string;
    onPrimary?: string;
    background?: string;
    surface?: string;
    text?: string;
    muted?: string;
    border?: string;
}
/**
 * Bucketed dimension scale (sm/md/lg) with the full observed set kept
 * for prose. Empty `observed` means no evidence was found; bucket fields
 * stay undefined in that case rather than guessing.
 */
export interface DimensionScale {
    sm?: string;
    md?: string;
    lg?: string;
    observed: string[];
}
/**
 * Structured per-component token detail. Filled when a recognizable
 * component selector (e.g., `.btn-primary`, `.card`) appears in extracted
 * CSS. Values are raw token strings, not token references — the writer is
 * responsible for cross-referencing back to `colors.*` / `rounded.*` once
 * the rich DESIGN.md template lands.
 */
export interface ComponentTokenDetail {
    name: string;
    backgroundColor?: string;
    textColor?: string;
    borderColor?: string;
    borderRadius?: string;
    padding?: string;
    boxShadow?: string;
}
export interface InspirationDesignSignals {
    brand: {
        title?: string;
        description?: string;
        siteName?: string;
        tone: string[];
    };
    typography: {
        headingFamilies: string[];
        bodyFamilies: string[];
        weights: string[];
        scaleSamples: string[];
        /** Families parsed from Google Fonts stylesheet link tags. */
        googleFontFamilies?: string[];
        /** Parsed `@font-face` declarations from static CSS. */
        fontFaces?: FontFaceEvidence[];
        /**
         * Display + body typography tokens shaped for DESIGN.md `typography`
         * group. Present only when CSS rules with matching selectors surface
         * concrete metrics.
         */
        tokens?: {
            display?: TypographyToken;
            body?: TypographyToken;
        };
    };
    colors: {
        palette: string[];
        themeColor?: string;
        accents: string[];
        /** Inferred semantic role assignments for DESIGN.md `colors` group. */
        roles?: ColorRoles;
    };
    layout: {
        sections: string[];
        structureNotes: string[];
    };
    components: string[];
    motionCues: string[];
    iconography: string[];
    /** Spacing dimension scale evidence for DESIGN.md `spacing` group. */
    spacing?: DimensionScale;
    /** Border-radius dimension scale evidence for DESIGN.md `rounded` group. */
    rounded?: DimensionScale;
    /** Raw `box-shadow` declarations observed. */
    shadows?: string[];
    /** Raw `transition*` declarations observed. */
    transitions?: string[];
    /** Responsive breakpoint conditions parsed from `@media (...)`. */
    breakpoints?: string[];
    /** Structured component token detail for DESIGN.md `components` group. */
    componentDetails?: ComponentTokenDetail[];
    signalDensity: number;
}
export interface InspirationExtractionInput {
    urls: string[];
    prompt: string;
    sourceContext?: SourceContextInput;
    slotCount: number;
    fetcher?: InspirationFetcher;
    /**
     * Test seam for the signal extractor — production wires the default. Keeps
     * unit tests deterministic against fixture HTML without re-implementing
     * the regex pipeline. The optional `extraCss` argument lets the
     * orchestrator pass merged linked-stylesheet text without storing it in
     * the cache.
     */
    signalExtractor?: (html: string, options?: {
        sourceUrl?: string;
        extraCss?: string;
    }) => InspirationDesignSignals;
    /**
     * Test seam for the linked-CSS fetcher. Production wires
     * `defaultLinkedCssFetcher`; tests inject a deterministic implementation
     * keyed by URL so external stylesheet ingestion can be exercised without
     * outbound network access. Setting this to a no-op fetcher disables
     * linked-CSS ingestion entirely.
     */
    cssFetcher?: LinkedCssFetcher;
    /**
     * Persistent runtime design context cache. When provided, the extractor
     * looks up each inspiration URL by normalized cache key before fetching
     * and writes successful extractions back so repeat requests with the same
     * link can reuse prior design context. Callers MUST scope the store to
     * runtime user data — bundled catalog files (`src/services/templates/
     * designmd`) are never mutated by this code path.
     */
    store?: DesignContextStore;
    /**
     * When true, the extractor bypasses any otherwise reusable cache entry
     * and forces a fresh fetch + extract. Successful re-extraction still
     * updates the cache so subsequent reuse picks up the regenerated entry.
     * Wired from prompt phrases like "fresh", "latest", "current".
     */
    forceRefresh?: boolean;
    /**
     * Wall-clock source for freshness checks and cache timestamps. Defaults to
     * `Date.now`. Tests inject a deterministic clock so the stale branch can
     * be exercised without sleeping.
     */
    now?: () => number;
    /** Freshness window in milliseconds. Falls back to the store default. */
    freshnessMs?: number;
    /** Extractor/schema version for cache compatibility. Tests override. */
    schemaVersion?: string;
}
export interface InspirationCacheOutcomeMetadata {
    /** Coarse age bucket for the most recent cache reuse this call surfaced. */
    ageBucket: ReturnType<typeof ageBucketFor>;
    /** Coarse confidence bucket for the cached confidence value. */
    confidenceBucket: ReturnType<typeof confidenceBucketFor>;
    /** Freshness state when the entry was inspected. */
    freshness: FreshnessState;
}
export interface InspirationExtractionOutcome {
    /** Aligned to slotCount. `undefined` slots fall back to prompt direction. */
    entries: Array<DesignContextEntry | undefined>;
    warnings: string[];
    /**
     * Outcome metadata safe for telemetry — counts only, no URLs, snippets,
     * fetched HTML, or extracted strings. Callers MAY forward this to product
     * analytics; full URLs and page content MUST stay out of telemetry.
     */
    telemetry: {
        inspirationLinkCount: number;
        referenceLinkCount: number;
        successfulExtractions: number;
        lowSignalCount: number;
        fetchFailureCount: number;
        blockedTargetCount: number;
        mergeStrategy: 'merge' | 'separate' | 'none';
        /**
         * Cache outcome counts. Safe to forward to analytics — these are pure
         * counts of cache hit / miss / stale / version-mismatch / regeneration
         * decisions and never include URLs, fetched HTML, extracted text, or
         * file paths.
         */
        cache: {
            hitCount: number;
            missCount: number;
            staleCount: number;
            versionMismatchCount: number;
            lowConfidenceCount: number;
            regenerationCount: number;
            forcedRefresh: boolean;
        };
    };
    /**
     * Per-call cache reuse summary suitable for user-facing surfaces. Present
     * only when at least one cached entry was reused. Contains age and
     * confidence buckets, never raw URLs or extracted text.
     */
    cacheReuse?: InspirationCacheOutcomeMetadata;
    /**
     * Structured error code surfaced when every supplied inspiration URL fails
     * during fetch. Absent when URLs load but do not contain enough design signal.
     */
    errorCode?: 'INSPIRATION_FETCH_ALL_FAILED';
    /**
     * Human-readable companion to `errorCode`. Recommends a recovery action
     * (e.g. passing a local file via `assetUrls`). Safe to surface verbatim.
     */
    errorMessage?: string;
}
/**
 * Synchronous URL validator: enforces HTTP/HTTPS scheme and rejects literal
 * hostnames that match local/loopback/link-local patterns. DNS-resolved
 * checks live in `defaultInspirationFetcher` so the simple checks here can
 * run without IO during input validation.
 */
export declare const validateInspirationUrl: (rawUrl: string) => {
    ok: true;
    url: URL;
    normalized: string;
} | {
    ok: false;
    reason: string;
};
/**
 * Returns true for hostnames that are unambiguously local or private without
 * any DNS lookup. IPv4 / IPv6 literals get the private-range check;
 * hostname strings get the local-domain pattern check.
 */
export declare const isLocalLiteralHostname: (hostname: string) => boolean;
/**
 * Resolve hostname and check the resolved address against private/loopback/
 * link-local ranges. Used inside `defaultInspirationFetcher` before issuing
 * a fetch so users cannot point inspiration links at private network hosts
 * via DNS rebinding-style indirection.
 *
 * @effect Performs a DNS lookup via dns.promises.lookup
 */
export declare const isResolvedHostProtected: (hostname: string) => Promise<boolean>;
/**
 * Decide whether a URL discovered in the user message is design inspiration,
 * source/content reference, or unrelated context. Combines local heuristics
 * on the prompt with explicit role hints from `sourceContext.artifact`.
 *
 * `primary` role -> `reference` (treated as content source).
 * `inspiration` role -> `inspiration`.
 * `competitor` role -> `inspiration` (will merge as separate per-slot).
 * Otherwise prompt phrasing wins; default is `inspiration` because the user
 * provided the URL in a creation flow.
 */
export declare const inferLinkIntent: (input: {
    url: string;
    prompt: string;
    sourceContext?: SourceContextInput;
}) => LinkIntent;
/**
 * Classify a deduped URL list against the prompt + sourceContext. Picks an
 * overall mergeStrategy: when the user's message frames the links as
 * alternatives/competitors/options, return `'separate'`; otherwise `'merge'`.
 * Explicit `competitor` roles also force `'separate'`.
 */
export declare const classifyInspirationLinks: (input: {
    urls: string[];
    prompt: string;
    sourceContext?: SourceContextInput;
}) => InspirationLinkClassification;
/**
 * Default fetcher used by `extractInspirationDesignContext`. Performs a
 * pre-fetch DNS check, applies a timeout, caps response size, validates the
 * response content-type, and refuses non-HTML payloads. Treats remote page
 * content as untrusted data — does not execute, evaluate, or inline its
 * text as agent instructions.
 *
 * @effect Issues an outbound HTTPS/HTTP fetch and a DNS lookup. Aborts on
 *         timeout, redirect limit, or oversize payloads.
 */
export declare const defaultInspirationFetcher: InspirationFetcher;
/**
 * Discover absolute stylesheet URLs from `<link rel="stylesheet">` tags.
 * Resolves relative `href` values against `baseUrl`, deduplicates, and
 * returns at most `MAX_LINKED_STYLESHEETS` entries so the caller's fetch
 * budget stays bounded. Only HTTP/HTTPS targets are returned — `data:`,
 * `blob:`, and other schemes are dropped before any safety checks run.
 */
export declare const discoverLinkedStylesheetUrls: (html: string, baseUrl: string) => string[];
/**
 * Default linked-stylesheet fetcher. Mirrors `defaultInspirationFetcher`'s
 * pre-fetch DNS check, redirect-aware re-check, timeout, and byte cap, but
 * accepts `text/css` (or `text/plain`) content and uses tighter per-file
 * limits. Returned `css` is treated as untrusted data — callers must not
 * evaluate it or inline it as agent instructions.
 *
 * @effect Issues an outbound HTTPS/HTTP fetch and a DNS lookup. Aborts on
 *         timeout or oversize payloads.
 */
export declare const defaultLinkedCssFetcher: LinkedCssFetcher;
/**
 * Fetch up to `MAX_LINKED_STYLESHEETS` linked stylesheets discovered in
 * the fetched HTML, honoring a cumulative byte budget. Returns the
 * concatenated CSS text and a count of how many sheets contributed.
 * The returned CSS is intentionally ephemeral — callers MUST NOT persist
 * or forward it to telemetry; only derived signal extractions may be
 * stored.
 */
export declare const fetchLinkedStylesheets: (html: string, baseUrl: string, fetcher: LinkedCssFetcher) => Promise<{
    css: string;
    fetchedCount: number;
    attemptedCount: number;
    byteTotal: number;
    skippedReasons: string[];
}>;
/**
 * Pure HTML signal extractor. Operates on raw fetched HTML and pulls
 * typography, color, layout, component, motion, brand, and tone signals
 * via regex without instantiating a DOM. Returns deterministic ordered
 * arrays so callers and tests can compare snapshots stably.
 *
 * `signalDensity` is a 0-100 fidelity-weighted score indicating how well
 * the extracted evidence can populate canonical DESIGN.md token groups and
 * sections. Callers can treat low scores as low-signal pages and fall back
 * to prompt direction.
 */
export declare const extractDesignSignals: (html: string, options?: {
    sourceUrl?: string;
    extraCss?: string;
}) => InspirationDesignSignals;
/**
 * Produce reusable DESIGN.md markdown with token frontmatter plus canonical
 * prose sections (`Overview` through `Do's and Don'ts`). The markdown avoids
 * embedding raw fetched HTML, source code, DOM dumps, screenshots, or
 * proprietary copied text.
 */
export declare const buildInspirationDesignContextMarkdown: (input: {
    signals: InspirationDesignSignals[];
    sources: Array<{
        url: string;
        label?: string;
    }>;
    merged: boolean;
}) => string;
export declare const extractInspirationDesignContext: (input: InspirationExtractionInput) => Promise<InspirationExtractionOutcome>;
/**
 * Re-export so callers wiring inspiration extraction can use the shared
 * prompt-URL extractor without importing from `sourceContext` directly.
 * Source research and SOURCE_CONTEXT.md remain owned by `sourceContext`;
 * this module only consumes the URL list.
 */
export { extractPromptUrls };
/**
 * Internal debug helper for ad-hoc engineering verification. Not registered
 * as an MCP tool, not exported from `index.ts`, and not advertised as a
 * product surface. Routes through the same validation, fetch, and markdown
 * generation as the MCP pipeline so debug output cannot drift from product
 * output.
 */
export declare const standaloneDebugExtract: (url: string, fetcher?: InspirationFetcher) => Promise<{
    url: string;
    ok: boolean;
    warnings: string[];
    markdown?: string;
}>;
//# sourceMappingURL=inspirationDesignContext.d.ts.map