/**
 * Sitemap regeneration + search-engine ping orchestration.
 *
 * Triggered as a best-effort side effect after public content is published,
 * updated, or removed (see `actions.ts` → `sitemap-notify` pending effect).
 * The CMS serves `/sitemap.xml` dynamically, so "regeneration" here means:
 *   1. bump `sitemapLastGeneratedAt` so the Settings/Technical UI reflects the
 *      change, and
 *   2. invalidate the sitemap cache tag so the next request rebuilds it.
 *
 * Pinging is **production-gated** and **SSRF-aware**:
 *   - Pings only fire when the resolved environment is `production` (or the
 *     caller explicitly opts in via `allowNonProduction`), so preview/local
 *     deploys never notify Google/Bing about throwaway URLs.
 *   - The site URL is validated as a public http(s) URL before it's embedded
 *     in a ping request, so a misconfigured `siteUrl` can't point search
 *     engines (or our own fetch) at an internal address.
 *
 * Note on endpoints: Google retired its standalone sitemap-ping endpoint in
 * 2023 (it now returns 404) and recommends discovery via robots.txt / Search
 * Console instead. We keep the call for completeness/back-compat but treat any
 * non-2xx response as a soft failure — Bing's endpoint still honors pings.
 */
import type { SeoModuleSettings } from './config-store.js';
export interface SitemapPingTarget {
    name: string;
    url: string;
}
/** Build the canonical `/sitemap.xml` URL from a configured site URL. */
export declare function buildSitemapUrl(siteUrl: string | null | undefined): string | null;
/** Search-engine ping targets for a given (already validated) sitemap URL. */
export declare function buildSearchEnginePings(sitemapUrl: string): SitemapPingTarget[];
/** IndexNow submission endpoint (a shared endpoint relays to all participants). */
export declare const INDEXNOW_ENDPOINT = "https://api.indexnow.org/indexnow";
export interface IndexNowSubmission {
    host: string;
    key: string;
    keyLocation: string;
    urlList: string[];
}
/**
 * Build the IndexNow submission body for a set of changed URLs.
 *
 * IndexNow (Bing, Yandex, Seznam, Naver, …) is URL-based — unlike the legacy
 * sitemap pings, it notifies engines of the *specific* URLs that changed for
 * near-instant (re)crawling. Returns null when there's no key or no in-host
 * URLs to submit (every URL must share the sitemap host).
 */
export declare function buildIndexNowSubmission(params: {
    key: string | null | undefined;
    keyLocation: string | null | undefined;
    changedUrls: string[];
}): IndexNowSubmission | null;
/**
 * Default debounce window for the expensive half of the cycle (timestamp write
 * + search-engine ping). Bursts of publishes (bulk imports, "publish all")
 * collapse to one regeneration per window so we don't hammer the single hot
 * `__seo_config__` row or spam search engines. Cache invalidation is NOT
 * debounced — it's cheap and must happen on every change for correctness.
 */
export declare const DEFAULT_SITEMAP_DEBOUNCE_MS = 60000;
export interface SitemapNotifyOptions {
    settings: Pick<SeoModuleSettings, 'sitemapEnabled' | 'autoRegenerateSitemapOnPublish' | 'pingSearchEnginesOnPublish'>;
    /** Configured public site URL (e.g. from `NEXT_PUBLIC_SITE_URL` or seo.siteUrl). */
    siteUrl?: string | null;
    /** Explicit environment override; defaults to `resolveSeoEnvironment()`. */
    environment?: string;
    /** ISO timestamp of the last regeneration, used to debounce the write + ping. */
    lastGeneratedAt?: string | null;
    /** Debounce window in ms (default {@link DEFAULT_SITEMAP_DEBOUNCE_MS}). */
    debounceMs?: number;
    /** Injectable fetch for tests; defaults to global `fetch`. */
    fetchImpl?: typeof fetch;
    /** Bypass the production gate (tests / explicit opt-in only). */
    allowNonProduction?: boolean;
    /** Per-ping timeout in ms (default 5000). */
    timeoutMs?: number;
    /**
     * Absolute URLs of the content that just changed, for IndexNow submission.
     * When omitted/empty, IndexNow is skipped (legacy sitemap pings still fire).
     */
    changedUrls?: string[];
    /** IndexNow key (from `INDEXNOW_KEY`). When absent, IndexNow is disabled. */
    indexNowKey?: string | null;
    /** Public URL of the IndexNow key file (served at /api/cms/indexnow-key.txt). */
    indexNowKeyLocation?: string | null;
}
export interface SitemapNotifyResult {
    /**
     * Whether the caller should drop the sitemap cache tag. True on every
     * sitemap-relevant change (not debounced) so the next request rebuilds.
     */
    invalidateCache: boolean;
    /**
     * Whether the caller should persist a fresh `sitemapLastGeneratedAt`. Only
     * true once per debounce window — this is the write that was amplifying.
     */
    regenerated: boolean;
    sitemapUrl: string | null;
    /** Names of search engines successfully pinged (2xx). */
    pinged: string[];
    /** Targets that were not pinged, with a machine-readable reason. */
    skipped: Array<{
        target: string;
        reason: string;
    }>;
}
/**
 * Decide what to do after a public-content change and perform the pings.
 * Pure-ish: all I/O goes through `fetchImpl` and the result tells the caller
 * whether to persist a regeneration timestamp. Never throws — sitemap upkeep
 * must not fail a content write that already committed.
 */
export declare function notifySitemapOnPublish(opts: SitemapNotifyOptions): Promise<SitemapNotifyResult>;
//# sourceMappingURL=sitemap-notify.d.ts.map