/**
 * SEO scoring model.
 *
 * Pure, dependency-light functions that turn a page/post's metadata + content
 * into an explainable 0-100 score, and aggregate per-category signals into a
 * site-wide score. Nothing here is persisted directly — the audit engine
 * (Phase 2) calls these and snapshots the results into `SeoAuditRun` /
 * `SeoIssue` rows, while the Content SEO table recomputes page scores on read.
 *
 * The score is intentionally NOT a mystery number: every result carries a
 * `checks` array describing exactly which points were earned/lost and why, so
 * the admin UI can show editors what to fix. The unit tests in
 * `__tests__/seo/score.test.ts` are the source of truth for the weights.
 */
export type SeoGrade = 'good' | 'fair' | 'poor' | 'critical';
export type SeoCheckStatus = 'pass' | 'warn' | 'fail';
/** One explainable line item in a page score. */
export interface SeoScoreCheck {
    id: string;
    label: string;
    /** Points earned (0..max). */
    points: number;
    /** Maximum points this check contributes. */
    max: number;
    status: SeoCheckStatus;
    message: string;
}
export interface PageSeoScoreResult {
    score: number;
    grade: SeoGrade;
    checks: SeoScoreCheck[];
}
/** The metadata + content subset a page score depends on. */
export interface PageSeoScoreInput {
    title?: string | null;
    slug?: string | null;
    url?: string | null;
    /** Raw HTML or plain content body, used for H1 + length checks. */
    content?: string | null;
    metaTitle?: string | null;
    metaDescription?: string | null;
    focusKeyword?: string | null;
    canonicalUrl?: string | null;
    ogTitle?: string | null;
    ogDescription?: string | null;
    ogImage?: string | null;
    structuredDataType?: string | null;
    noindex?: boolean | null;
    /** True when this content is intended to be public/indexable. */
    shouldBeIndexable?: boolean;
    /** Number of internal links that failed validation, when known. */
    brokenInternalLinks?: number;
    /** Pre-computed word count; falls back to counting `content`. */
    wordCount?: number | null;
}
/** Page score weights. Must sum to 100. */
export declare const PAGE_SEO_WEIGHTS: {
    readonly metaTitlePresent: 10;
    readonly metaTitleLength: 5;
    readonly metaDescPresent: 10;
    readonly metaDescLength: 5;
    readonly focusKeyword: 8;
    readonly canonical: 7;
    readonly h1: 10;
    readonly contentLength: 10;
    readonly ogImage: 8;
    readonly ogTitleDesc: 5;
    readonly structuredData: 7;
    readonly internalLinks: 5;
    readonly indexable: 10;
};
/** Site score category weights (spec). Must sum to 100. */
export declare const SITE_SEO_WEIGHTS: {
    readonly content: 30;
    readonly technical: 25;
    readonly linkRedirect: 20;
    readonly structuredSocial: 15;
    readonly performance: 10;
};
/** Map a 0-100 score to a grade. Aligns with the Content SEO table colours. */
export declare function gradeForSeoScore(score: number): SeoGrade;
/**
 * Count H1 headings in content that may be HTML or Markdown (case-insensitive
 * for HTML tags, ATX `#`/Setext `===` for Markdown), so markdown-bodied posts
 * aren't penalised for a "missing" H1 that is actually present.
 */
export declare function countH1(html: string): number;
/**
 * Compute a page/post SEO score (0-100) with an explainable breakdown.
 *
 * Points are additive per {@link PAGE_SEO_WEIGHTS}; "warn" checks earn partial
 * credit. The total is clamped to 0-100 and rounded.
 */
export declare function calculatePageSeoScore(input: PageSeoScoreInput): PageSeoScoreResult;
export interface SiteScoreCategory {
    /** 0-100 sub-score for this category. */
    score: number;
    weight: number;
}
export interface SiteSeoScoreInput {
    /** 0-100 — metadata completeness/uniqueness across content. */
    content: number;
    /** 0-100 — crawl/index health (sitemap, robots, canonicals, noindex). */
    technical: number;
    /** 0-100 — internal link + redirect health. */
    linkRedirect: number;
    /** 0-100 — structured data + social metadata coverage. */
    structuredSocial: number;
    /** 0-100 — performance + search signals (defaults neutral when unknown). */
    performance?: number;
}
export interface SiteSeoScoreBreakdownItem {
    category: keyof typeof SITE_SEO_WEIGHTS;
    score: number;
    weight: number;
    /** Weighted contribution to the final score. */
    contribution: number;
}
export interface SiteSeoScoreResult {
    score: number;
    grade: SeoGrade;
    breakdown: SiteSeoScoreBreakdownItem[];
}
/**
 * Combine per-category sub-scores into a weighted 0-100 site score.
 *
 * Performance defaults to 70 (neutral) when not supplied, so sites without a
 * connected performance source aren't unfairly penalised — the weight is still
 * applied so connecting Search Console can only improve the signal's accuracy.
 */
export declare function calculateSiteSeoScore(input: SiteSeoScoreInput): SiteSeoScoreResult;
//# sourceMappingURL=score.d.ts.map