/**
 * SEO service — typed client over the cms-core SEO REST endpoints.
 *
 * Every SEO admin component reads/writes through this module (never raw
 * `cmsApi` / `fetch`), so the network contract lives in one place. Fetchers
 * return typed data with safe fallbacks; mutations return `{ error?: string }`.
 *
 * Endpoint paths here are the contract implemented by cms-core
 * `packages/cms-core/src/api/handlers.ts` across phases 2-3 and 6.
 */
import type { BrandAlignmentScoreResult } from '@actuate-media/cms-core/brand-voice';
import type { SEOAnalysisResult } from '@actuate-media/cms-core/seo/analysis';
export type SeoGrade = 'good' | 'fair' | 'poor' | 'critical';
export type SeoSeverity = 'critical' | 'warning' | 'info';
export type SeoIssueStatus = 'open' | 'ignored' | 'resolved' | 'recurring';
export type SeoIssueCategory = 'content' | 'technical' | 'redirects' | 'media' | 'performance' | 'schema' | 'social' | 'indexing';
export type RedirectStatusCode = 301 | 302 | 307 | 308 | 410;
export interface SeoSiteScore {
    score: number;
    grade: SeoGrade;
    /** Change vs the previous audit run, e.g. +6. */
    delta: number | null;
    breakdown: {
        category: string;
        score: number;
        weight: number;
        contribution: number;
    }[];
}
export interface SeoMetric {
    label: string;
    value: string;
    helper: string;
    /** Optional trend direction for the helper colour. */
    trend?: 'up' | 'down' | 'flat';
}
export interface SeoIssue {
    id: string;
    auditRunId: string | null;
    entityType: string | null;
    entityId: string | null;
    entityTitle: string | null;
    url: string | null;
    severity: SeoSeverity;
    category: SeoIssueCategory;
    type: string;
    title: string;
    description: string | null;
    impact: string | null;
    recommendation: string | null;
    status: SeoIssueStatus;
    fixable: boolean;
    fixActionType: string | null;
    relatedEntityIds: string[];
    source: string;
    firstDetectedAt: string | null;
    lastDetectedAt: string | null;
    resolvedAt: string | null;
}
export interface QuickWin {
    id: string;
    title: string;
    explanation: string;
    impact: 'High' | 'Medium' | 'Low';
    issueId: string | null;
    fixActionType: string | null;
}
export interface SearchPerformanceRow {
    url: string;
    title: string;
    impressions: number;
    clicks: number;
    ctr: number;
    averagePosition: number;
}
export interface SeoOverview {
    siteScore: SeoSiteScore;
    metrics: SeoMetric[];
    issues: SeoIssue[];
    issuesSummary: {
        total: number;
        critical: number;
        warning: number;
        info: number;
    };
    quickWins: QuickWin[];
    searchPerformance: SearchPerformanceRow[];
    searchConsoleConnected: boolean;
    lastAuditRunId: string | null;
}
export declare function fetchSeoOverview(): Promise<SeoOverview>;
export declare function fetchSearchPerformance(params?: {
    limit?: number;
}): Promise<SearchPerformanceRow[]>;
/** Schema.org types available in document SEO editors. */
export declare const SEO_SCHEMA_TYPES: readonly ["Article", "BlogPosting", "WebPage", "FAQPage", "Product", "Event", "LocalBusiness", "HowTo", "Recipe"];
export type SeoSchemaType = (typeof SEO_SCHEMA_TYPES)[number];
export interface SeoContentRecord {
    id: string;
    entityType: 'page' | 'post';
    entityId: string;
    title: string;
    url: string;
    canonicalUrl: string | null;
    /** Rendered public title (after site title template). */
    metaTitle: string | null;
    /** Stored page-specific portion for the `%page%` token. */
    metaTitlePage?: string | null;
    siteName?: string | null;
    titleTemplate?: string | null;
    metaDescription: string | null;
    focusKeyword: string | null;
    keyTakeaway: string | null;
    ogTitle: string | null;
    ogDescription: string | null;
    ogImageId: string | null;
    ogImage: string | null;
    twitterTitle: string | null;
    twitterDescription: string | null;
    twitterImageId: string | null;
    noindex: boolean;
    nofollow: boolean;
    structuredDataType: string | null;
    structuredData: Record<string, unknown> | null;
    /** llms.txt curation: AUTO (heuristic), ALWAYS (pin), NEVER (exclude). */
    llmsInclude: LlmsInclude;
    /** Curated agent-facing description for llms.txt (overrides the fallback). */
    llmsDescription: string | null;
    /** Section/grouping override in llms.txt (defaults to the collection). */
    llmsSection: string | null;
    /** Route this entry into the reserved `## Optional` section. */
    llmsOptional: boolean;
    seoScore: number;
    seoGrade: SeoGrade;
    updatedAt: string | null;
}
export type LlmsInclude = 'AUTO' | 'ALWAYS' | 'NEVER';
export type ContentSeoFilter = 'all' | 'pages' | 'posts';
export declare function fetchSeoContentRecords(): Promise<SeoContentRecord[]>;
export declare function fetchSeoContentRecord(entityType: string, entityId: string): Promise<SeoContentRecord | null>;
export interface SeoFieldPayload {
    metaTitle?: string;
    metaDescription?: string;
    canonicalUrl?: string;
    focusKeyword?: string;
    keyTakeaway?: string;
    ogTitle?: string;
    ogDescription?: string;
    ogImage?: string;
    twitterTitle?: string;
    twitterDescription?: string;
    twitterImage?: string;
    noindex?: boolean;
    nofollow?: boolean;
    structuredDataType?: string;
    structuredData?: Record<string, unknown>;
    llmsInclude?: LlmsInclude;
    llmsDescription?: string;
    llmsSection?: string;
    llmsOptional?: boolean;
}
export declare function fetchDocumentSeoAnalysis(documentId: string): Promise<SEOAnalysisResult>;
export declare function updateSeoFields(entityType: string, entityId: string, payload: SeoFieldPayload): Promise<{
    error?: string;
}>;
/** Pure search/filter over the content records (decoupled from network for tests). */
export declare function applyContentSeoQuery(records: SeoContentRecord[], query: {
    search?: string;
    filter?: ContentSeoFilter;
}): SeoContentRecord[];
export type SeoAuditScope = 'full' | 'content' | 'technical' | 'redirect';
export interface SeoAuditRun {
    id: string;
    status: 'RUNNING' | 'COMPLETED' | 'FAILED';
    scope: string;
    startedAt: string;
    finishedAt: string | null;
    siteScoreBefore: number | null;
    siteScoreAfter: number | null;
    pagesScanned: number;
    issuesFound: number;
    criticalCount: number;
    warningCount: number;
    infoCount: number;
    errorMessage: string | null;
}
export declare function runSeoAudit(scope?: SeoAuditScope): Promise<{
    run?: SeoAuditRun;
    error?: string;
}>;
export declare function fetchSeoAuditRuns(): Promise<SeoAuditRun[]>;
export declare function fetchSeoAuditRun(auditRunId: string): Promise<SeoAuditRun | null>;
export interface SeoIssueQuery {
    severity?: SeoSeverity | 'all';
    category?: SeoIssueCategory | 'all';
    status?: SeoIssueStatus | 'all';
    auditRunId?: string;
}
export declare function fetchSeoIssues(query?: SeoIssueQuery): Promise<SeoIssue[]>;
export declare function fetchSeoIssue(issueId: string): Promise<SeoIssue | null>;
export declare function resolveSeoIssue(issueId: string): Promise<{
    error?: string;
}>;
export declare function ignoreSeoIssue(issueId: string): Promise<{
    error?: string;
}>;
export declare function reopenSeoIssue(issueId: string): Promise<{
    error?: string;
}>;
export interface SeoFixFieldChange {
    field: string;
    label: string;
    before: string | boolean | null;
    after: string | boolean | null;
}
export interface SeoIssueFixSuggestion {
    autoFixable: boolean;
    source?: 'deterministic' | 'ai';
    fixStrategy?: 'redirect' | 'fix-link';
    aiUnavailable?: boolean;
    fingerprint: string;
    patch: Record<string, unknown>;
    changes: SeoFixFieldChange[];
    justification: string;
}
export declare function fetchSeoIssueFixSuggestion(issueId: string): Promise<{
    suggestion?: SeoIssueFixSuggestion;
    error?: string;
}>;
export declare function applySeoIssueFix(issueId: string, fingerprint: string): Promise<{
    issue?: SeoIssue;
    error?: string;
}>;
export interface SeoFixBriefExport {
    markdown: string;
    filename: string;
    issueCount: number;
}
export interface SeoFixBriefExportQuery {
    severity?: SeoSeverity | 'all';
    status?: SeoIssueStatus | 'all';
    auditRunId?: string;
    /** Default true — only issues needing dev/content handoff. */
    manualOnly?: boolean;
    /** Default true — embed cached AI content briefs when available. */
    includeContentBriefs?: boolean;
    /** Default true — embed cached topic research when available. */
    includeContentResearch?: boolean;
}
export declare function exportSeoFixBrief(query?: SeoFixBriefExportQuery): Promise<{
    data?: SeoFixBriefExport;
    error?: string;
}>;
/** Issue types with inline Approve fix in the Audit tab (keep in sync with cms-core). */
export declare const SEO_INLINE_FIX_ISSUE_TYPES: Set<string>;
export declare function isInlineSeoFixIssue(type: string): boolean;
export declare const SEO_CONTENT_BRIEF_ISSUE_TYPES: readonly ["thin-content", "missing-h1", "multiple-h1", "missing-alt-text"];
export declare function supportsSeoContentBrief(type: string): boolean;
export interface SeoContentBriefSection {
    heading: string;
    bullets: string[];
}
export interface SeoContentBrief {
    issueType: string;
    entityId: string;
    fingerprint: string;
    generatedAt: string;
    summary: string;
    suggestedH1: string | null;
    targetWordCount: number | null;
    topics: string[];
    sections: SeoContentBriefSection[];
    keyTakeawayDraft: string | null;
    geoNote: string | null;
}
export declare function fetchSeoContentBrief(issueId: string): Promise<{
    supported?: boolean;
    brief?: SeoContentBrief | null;
    stale?: boolean;
    error?: string;
}>;
export declare function generateSeoContentBrief(issueId: string): Promise<{
    brief?: SeoContentBrief;
    error?: string;
}>;
export declare const SEO_RESEARCH_ISSUE_TYPES: readonly ["thin-content"];
export declare function supportsSeoContentResearch(type: string): boolean;
export interface SeoContentResearchCompetitor {
    url: string;
    title: string;
    note: string;
}
export interface SeoContentResearch {
    issueType: string;
    entityId: string;
    fingerprint: string;
    generatedAt: string;
    focusKeyword: string | null;
    suggestedWordCount: number | null;
    outline: string[];
    faqCandidates: string[];
    entitiesToMention: string[];
    competitorInsights: SeoContentResearchCompetitor[];
    summary: string;
}
export declare function fetchSeoContentResearch(issueId: string): Promise<{
    supported?: boolean;
    research?: SeoContentResearch | null;
    stale?: boolean;
    error?: string;
}>;
export declare function generateSeoContentResearch(issueId: string, competitorUrls?: string[]): Promise<{
    research?: SeoContentResearch;
    error?: string;
}>;
export declare function researchAndBriefSeoIssue(issueId: string, competitorUrls?: string[]): Promise<{
    research?: SeoContentResearch | null;
    brief?: SeoContentBrief;
    error?: string;
}>;
export interface BatchContentBriefResult {
    generated: number;
    skipped: number;
    failed: number;
    results: Array<{
        issueId: string;
        status: 'generated' | 'skipped' | 'failed';
        error?: string;
    }>;
}
export interface BatchContentBriefQuery {
    severity?: SeoSeverity | 'all';
    status?: SeoIssueStatus | 'all';
    issueIds?: string[];
    skipExisting?: boolean;
    includeResearch?: boolean;
}
export declare function batchGenerateSeoContentBriefs(query?: BatchContentBriefQuery): Promise<{
    data?: BatchContentBriefResult;
    error?: string;
}>;
export interface SitemapStatus {
    sitemapUrl: string;
    lastGeneratedAt: string | null;
    pagesIncluded: number;
    pagesExcluded: number;
    autoRegenerateOnPublish: boolean;
    errors: string[];
    warnings: string[];
}
export interface CrawlSettings {
    indexEntireSite: boolean;
    includeImagesInSitemap: boolean;
    includePostsInSitemap: boolean;
    sitemapEnabled: boolean;
    autoRegenerateSitemapOnPublish: boolean;
    pingSearchEnginesOnPublish: boolean;
}
export declare function fetchSitemapStatus(): Promise<SitemapStatus | null>;
export declare function regenerateSitemap(): Promise<{
    status?: SitemapStatus;
    error?: string;
}>;
export declare function fetchCrawlSettings(): Promise<CrawlSettings | null>;
export declare function updateCrawlSettings(payload: Partial<CrawlSettings>): Promise<{
    error?: string;
}>;
export interface AiCrawlerRow {
    bot: string;
    surface: string;
    category: string;
    hits: number;
    firstSeenAt: string;
    lastSeenAt: string;
}
export interface AiCrawlerActivity {
    enabled: boolean;
    rows: AiCrawlerRow[];
    totals: {
        hits: number;
        bots: number;
        honeypot: number;
    };
}
export declare function fetchAiCrawlerActivity(): Promise<AiCrawlerActivity>;
export interface RobotsConfig {
    body: string;
    generated: boolean;
}
export interface RobotsValidation {
    valid: boolean;
    blocksEntireSite: boolean;
    errors: string[];
    warnings: string[];
}
export declare function fetchRobotsTxt(): Promise<RobotsConfig | null>;
export declare function updateRobotsTxt(body: string): Promise<{
    error?: string;
}>;
/** Client-side robots.txt validation (mirrors server-side checks). */
export declare function validateRobotsTxt(body: string): RobotsValidation;
export interface RedirectRule {
    id: string;
    type: RedirectStatusCode;
    fromPath: string;
    toPath: string;
    enabled: boolean;
    priority: number;
    preserveQuery: boolean;
    hits: number;
    lastHitAt: string | null;
    stale: boolean;
    source: string;
    notes: string | null;
    createdAt: string;
    updatedAt: string;
}
export interface RedirectOverview {
    activeRedirects: number;
    staleRedirects: number;
    notFoundCount: number;
    notFoundHits: number;
    chainsAndLoops: number;
    trafficRecovered: number;
}
export interface Redirect404 {
    id: string;
    path: string;
    hits: number;
    lastSeenAt: string;
}
export interface RedirectSuggestion {
    id: string;
    fromPath: string;
    toPath: string;
    confidence: number;
    reason: string | null;
    status: 'open' | 'accepted' | 'dismissed';
    hits: number;
    trend: string | null;
}
export interface RedirectChain {
    id: string;
    kind: 'chain' | 'loop';
    hops: string[];
    suggestedFrom: string;
    suggestedTo: string;
}
export declare function fetchRedirectOverview(): Promise<RedirectOverview>;
export declare function fetchRedirectRules(): Promise<RedirectRule[]>;
export interface RedirectRulePayload {
    type: RedirectStatusCode;
    fromPath: string;
    toPath: string;
    enabled?: boolean;
    preserveQuery?: boolean;
    notes?: string;
}
export declare function createRedirectRule(payload: RedirectRulePayload): Promise<{
    error?: string;
}>;
export declare function updateRedirectRule(redirectId: string, payload: Partial<RedirectRulePayload>): Promise<{
    error?: string;
}>;
export declare function deleteRedirectRule(redirectId: string): Promise<{
    error?: string;
}>;
export declare function fetchRedirectChains(): Promise<RedirectChain[]>;
export declare function flattenRedirectChain(chainId: string): Promise<{
    error?: string;
}>;
export declare function fetchRedirectSuggestions(): Promise<RedirectSuggestion[]>;
export interface RedirectRecoverySettings {
    aiRerank: boolean;
    autoApply: boolean;
    autoApplyMinConfidence: number;
}
export declare function fetchRedirectRecoverySettings(): Promise<RedirectRecoverySettings | null>;
export declare function saveRedirectRecoverySettings(settings: Partial<RedirectRecoverySettings>): Promise<{
    error?: string;
}>;
export declare function generate404RecoverySuggestions(): Promise<{
    error?: string;
    autoApplied?: number;
}>;
export declare function acceptRedirectSuggestion(suggestionId: string): Promise<{
    error?: string;
}>;
export declare function dismissRedirectSuggestion(suggestionId: string): Promise<{
    error?: string;
}>;
export declare function exportRedirectsCsv(): Promise<{
    csv?: string;
    error?: string;
}>;
export declare function importRedirectsCsv(csv: string): Promise<{
    imported?: number;
    errors?: string[];
    error?: string;
}>;
export interface SeoAiResult {
    text?: string;
    alternatives?: string[];
    structuredData?: Record<string, unknown>;
    brandAlignment?: BrandAlignmentScoreResult;
    /** True when the AI provider is not configured (graceful fallback). */
    unavailable?: boolean;
}
export declare function generateSeoField(field: 'metaTitle' | 'metaDescription' | 'ogTitle' | 'ogDescription' | 'focusKeyword' | 'keyTakeaway', context: {
    entityType: string;
    entityId: string;
}): Promise<SeoAiResult>;
export declare function explainSeoIssue(issueId: string): Promise<SeoAiResult>;
export declare function generateStructuredData(context: {
    entityType: string;
    entityId: string;
    schemaType: string;
}): Promise<SeoAiResult>;
export declare function summarizeSeoAudit(): Promise<SeoAiResult>;
export interface LinkGraphEntityRef {
    id: string;
    title: string;
    url: string;
    path: string;
    collection: string;
    entityType: 'page' | 'post';
    isHome: boolean;
}
export interface LinkGraphSnapshot {
    scannedAt: string;
    postsCrawled: number;
    internalLinks: number;
    externalLinks: number;
    internalRatio: number;
    orphanCount: number;
    orphaned: LinkGraphEntityRef[];
    linkCoveragePercent: number;
    underLinked: Array<LinkGraphEntityRef & {
        outboundInternal: number;
    }>;
    brokenLinkCount: number;
    aiIndexLastRunAt: string | null;
    aiIndexReady: boolean;
}
export interface LinkHealthIssue {
    id: string;
    page: string;
    url: string;
    status: number;
    type: string;
}
export interface LinkSuggestion {
    sourceEntityId: string;
    sourceTitle: string;
    sourceUrl: string;
    anchorText: string;
    confidence: number;
    excerpt: string;
}
export declare function fetchLinkGraphSnapshot(): Promise<LinkGraphSnapshot>;
export declare function runLinkAiIndex(): Promise<{
    data?: {
        indexedAt: string;
        entitiesIndexed: number;
        aiAvailable: boolean;
        message: string;
    };
    error?: string;
}>;
export declare function fetchLinkSuggestions(input: {
    targetEntityId: string;
    targetEntityType: 'page' | 'post';
    limit?: number;
}): Promise<{
    data?: {
        target: {
            id: string;
            title: string;
            url: string;
        };
        suggestions: LinkSuggestion[];
    };
    error?: string;
}>;
export declare function fetchLinkHealthIssues(): Promise<{
    data?: {
        issues: LinkHealthIssue[];
        checked: number;
        truncated: boolean;
    };
    error?: string;
}>;
//# sourceMappingURL=seo-service.d.ts.map