import { type RobotsVerdict } from './robots.js'; /** * 네이버 서치어드바이저 — 검색 노출·색인 도구. * * 서치어드바이저에는 **공개 웹마스터 API 가 없다**(사이트 등록·사이트맵/RSS 제출·리포트는 콘솔 전용). * 자동화할 수 있는 면은 두 가지뿐이라 그것만 다룬다: * - IndexNow: 네이버가 참여 엔진이다. 새/수정/삭제 URL 을 즉시 알린다. 인증 = 사이트에 올린 키 파일. * - 크롤러 관점 점검: 네이버 검색로봇(Yeti)이 보는 robots.txt·상태 코드·리다이렉트·메타 태그를 확인한다. * 어느 쪽도 `~/.mimi-seed/` 자격증명을 쓰지 않는다. * * 점검 대상 사이트의 응답(HTML·robots.txt·헤더)은 **적대적 입력**으로 다룬다: 본문은 상한까지만 읽고, * 파싱은 선형 스캔으로만 한다. 정규식 백트래킹이나 무한 버퍼링 한 번이면 stdio 서버 전체가 멈춘다. */ /** 네이버가 공개한 검색로봇 User-Agent. UA 로 봇을 막는 서버를 잡아내려고 그대로 보낸다. */ export declare const YETI_USER_AGENT = "Mozilla/5.0 (compatible; Yeti/1.1; +https://naver.me/spd)"; /** indexnow.org/searchengines.json 에 등록된 네이버 엔드포인트. */ export declare const NAVER_INDEXNOW_ENDPOINT = "https://searchadvisor.naver.com/indexnow"; /** IndexNow 프로토콜: POST 1회 최대 URL 수. */ export declare const INDEXNOW_MAX_URLS = 10000; /** IndexNow 프로토콜: 8–128자, 영문·숫자·대시. */ export declare const INDEXNOW_KEY_PATTERN: RegExp; /** RFC 9309: 크롤러는 robots.txt 를 최소 500 KiB 까지 해석해야 한다. 그 이상은 버린다. */ export declare const ROBOTS_MAX_BYTES: number; /** HTML 은 이만큼만 읽는다 — head·본문 추정에는 충분하고 메모리는 묶인다. */ export declare const HTML_MAX_BYTES: number; /** * 응답 본문을 `maxBytes` 까지만 읽고 나머지는 끊는다. 인코딩은 content-type 의 charset * (EUC-KR 등 레거시 한국어 페이지 포함), 모르면 UTF-8. BOM 은 TextDecoder 가 벗긴다. */ export declare function readCapped(res: Response, maxBytes: number): Promise<{ text: string; truncated: boolean; }>; export interface PageHead { title?: string; description?: string; canonical?: string; /** `` — 상대 canonical 을 풀 때 쓴다. */ base?: string; lang?: string; og: { title?: string; description?: string; image?: string; url?: string; }; /** `` 와 `` 의 지시어(소문자). */ robots: string[]; naverSiteVerification: boolean; /** script/style 을 뺀 원본 HTML 의 보이는 글자 수. */ textLength: number; scriptCount: number; } export declare function decodeEntities(value: string): string; /** 속성 문자열 파서. HTML 처럼 같은 이름은 **처음 것**이 이긴다. */ export declare function parseAttrs(src: string): Record; export declare function parseHead(html: string): PageHead; export interface XRobots { /** 이 크롤러에 확실히 적용되는 지시어. */ applies: string[]; /** * 다른 봇 접두어(`googlebot: …`) 뒤에 콤마로 이어진 지시어. 같은 헤더의 연속이면 그 봇 전용이지만, * 헤더가 여러 개면 fetch 가 `, ` 로 합쳐 버려 **접두어 없는 별도 헤더**였을 수도 있다 — 구분할 수 없다. */ ambiguous: string[]; } /** * `X-Robots-Tag` 에서 이 크롤러에 적용되는 지시어를 뽑는다. * UA 접두어가 없는 지시어는 모두에게, `yeti: …` 는 Yeti 에게, `googlebot: …` 은 건너뛴다. */ export declare function xRobotsDirectives(header: string | null, crawler?: string): XRobots; /** HTTP `Link: <…>; rel="canonical"` 헤더의 대상. */ export declare function linkHeaderCanonical(header: string | null): string | undefined; export type IssueLevel = 'error' | 'warn' | 'info'; export interface PageIssue { level: IssueLevel; code: string; message: string; } export interface RedirectHop { url: string; status: number; location: string; } export interface PageCheck { url: string; finalUrl: string; status: number; contentType: string | null; redirects: RedirectHop[]; robotsTxt: { url: string; status: number | null; verdict: RobotsVerdict | null; sitemaps: string[]; }; directives: { meta: string[]; header: string[]; headerAmbiguous: string[]; }; head: PageHead | null; issues: PageIssue[]; summary: Record; } /** 네이버 검색로봇(Yeti) 관점에서 URL 1개를 점검한다. 쓰기 없음. */ export declare function checkPage(input: string): Promise; export interface IndexNowInput { urls: string[]; key: string; /** 키 파일이 사이트 루트(`/.txt`)가 아닐 때만. */ keyLocation?: string; } export interface IndexNowResult { endpoint: string; status: number; host: string; keyLocation: string; submitted: number; } /** * 네이버 IndexNow 로 URL 변경을 알린다. * * 보내기 전에 키 파일을 직접 받아 key 와 같은지 확인한다 — 틀린 키는 엔드포인트가 403 만 돌려주고, * 같은 호스트에 틀린 키로 반복 제출하면 스팸 판정 위험만 커진다. 같은 URL 재제출은 안전하다. */ export declare function submitIndexNow({ urls, key, keyLocation }: IndexNowInput): Promise;