/** * IndexNow bildirimi (Bing + Yandex; Google desteklemiyor). * * Anahtar dosyası: public/.txt — canlıda https://kolaytercih.com/.txt * olarak sunulur; IndexNow her bildirimde bu dosyayı okuyup anahtarı doğrular. * Anahtar gizli değildir (dosya zaten herkese açık), ama değiştirilirse * public/ altındaki dosya da birlikte değişmeli. * * Kullanım (canlıda 200 dönen adresler için, yayından SONRA): * pnpm indexnow https://kolaytercih.com/rehber/ [...] * pnpm indexnow --rehber # content/rehber altındaki tüm yazılar * pnpm indexnow --sitemap # canlı sitemap.xml'deki tüm adresler (10.000'e kadar) * * Bing Webmaster → IndexNow sekmesinde alınan bildirimler görünür; Yandex * Webmaster'da "Indexing → IndexNow" altında. Aynı adres günde bir kez yeter. */ import fs from "node:fs"; import path from "node:path"; const HOST = "kolaytercih.com"; const SITE = `https://${HOST}`; const UC = "https://api.indexnow.org/indexnow"; function anahtarOku(): string { const dizin = path.join(process.cwd(), "public"); const dosya = fs .readdirSync(dizin) .find((f) => /^[0-9a-f]{32}\.txt$/.test(f)); if (!dosya) { throw new Error("indexnow: public/ altında <32 hex>.txt anahtar dosyası yok"); } const anahtar = fs.readFileSync(path.join(dizin, dosya), "utf8").trim(); if (anahtar !== dosya.replace(/\.txt$/, "")) { throw new Error(`indexnow: ${dosya} içeriği dosya adıyla eşleşmiyor`); } return anahtar; } function rehberAdresleri(): string[] { const dizin = path.join(process.cwd(), "content", "rehber"); return fs .readdirSync(dizin) .filter((f) => f.endsWith(".md")) .map((f) => `${SITE}/rehber/${f.replace(/\.md$/, "")}`); } async function sitemapAdresleri(): Promise { const res = await fetch(`${SITE}/sitemap.xml`); if (!res.ok) throw new Error(`indexnow: sitemap ${res.status}`); const xml = await res.text(); return [...xml.matchAll(/([^<]+)<\/loc>/g)].map((m) => m[1].trim()); } async function main() { const args = process.argv.slice(2); let adresler: string[]; if (args.includes("--rehber")) adresler = rehberAdresleri(); else if (args.includes("--sitemap")) adresler = await sitemapAdresleri(); else adresler = args.filter((a) => a.startsWith("http")); adresler = [...new Set(adresler)].filter((a) => a.startsWith(SITE)); if (adresler.length === 0) { console.error("indexnow: adres yok. Kullanım: pnpm indexnow | --rehber | --sitemap"); process.exit(1); } if (adresler.length > 10_000) { throw new Error("indexnow: tek istekte en fazla 10.000 adres"); } const key = anahtarOku(); const res = await fetch(UC, { method: "POST", headers: { "Content-Type": "application/json; charset=utf-8" }, body: JSON.stringify({ host: HOST, key, keyLocation: `${SITE}/${key}.txt`, urlList: adresler, }), }); // 200 = işlendi, 202 = alındı (anahtar sonra doğrulanacak), 4xx = hata. console.log(`indexnow: ${adresler.length} adres → HTTP ${res.status}`); if (!res.ok && res.status !== 202) { console.error(await res.text()); process.exit(1); } } main().catch((e) => { console.error(e); process.exit(1); });