All checks were successful
Deploy / deploy (push) Successful in 6m16s
GEO araştırması (docs/arastirma/2026-09-24-geo-seo) Dalga 1-2 uygulaması: - /llms.txt ve /feed.xml route'ları (getAllRehberler'den otomatik), head'de RSS linki - Article JSON-LD: author, image, mainEntityOfPage, publisher logo; görünür 'Yazan' satırı - robots: ClaudeBot ayrı grupta Crawl-delay 1 - scripts/indexnow.ts (pnpm indexnow) + public anahtar dosyası - bölüm sayfası açılışı veriden üretilen özgü cümleler (il/program/tür/kontenjan, taban aralığı, yıllık yön) - ana sayfa fiyat iddiasına kaynak; iki yazıda 23.000 -> 21.000+; beş yazıya 'Kısa cevap' açılışı - yeni yazı: vakif-universitesi-bursu-kesilir-mi (ÖSYM 2026 kılavuzu + YÖK ücret esasları) - YAYIN-KUYRUGU: IndexNow adımı ve aylık AI görünürlük rutini Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
93 lines
3.2 KiB
TypeScript
93 lines
3.2 KiB
TypeScript
/**
|
||
* IndexNow bildirimi (Bing + Yandex; Google desteklemiyor).
|
||
*
|
||
* Anahtar dosyası: public/<anahtar>.txt — canlıda https://kolaytercih.com/<anahtar>.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/<slug> [...]
|
||
* 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<string[]> {
|
||
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>([^<]+)<\/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 <url...> | --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);
|
||
});
|