// IndexNow: URL を検索エンジン(Bing・Yandex・Seznam・Naver 等)へ即時通知する。 // // 使い方(デプロイしてキーファイルが公開された状態で実行する): // 1) サイトマップの全URLを送る: npm run indexnow // 2) 特定URLだけ送る: node scripts/indexnow.mjs https://yasutakeyohei.com/foo/ ... // // 仕様: https://www.indexnow.org/documentation // キーは public/.txt(名前=中身)として公開する。 import { readFileSync, readdirSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { dirname, join } from "node:path"; const root = join(dirname(fileURLToPath(import.meta.url)), ".."); const HOST = "yasutakeyohei.com"; const KEY_RE = /^[A-Za-z0-9-]{8,128}$/; // public/ から IndexNow キーファイル(ファイル名=中身の .txt)を探す。 function findKey() { if (process.env.INDEXNOW_KEY) return process.env.INDEXNOW_KEY; for (const name of readdirSync(join(root, "public"))) { if (!name.endsWith(".txt")) continue; const stem = name.slice(0, -4); if (!KEY_RE.test(stem)) continue; if (readFileSync(join(root, "public", name), "utf-8").trim() === stem) { return stem; } } throw new Error("IndexNow キーファイル(public/.txt)が見つかりません"); } // 送るURLを集める(引数があればそれ、無ければ dist のサイトマップ)。 function collectUrls() { const args = process.argv.slice(2).filter((a) => a.startsWith("http")); if (args.length) return args; const dir = join(root, "dist"); const urls = []; for (const name of readdirSync(dir)) { if (!/^sitemap.*\.xml$/.test(name) || name === "sitemap-index.xml") continue; const xml = readFileSync(join(dir, name), "utf-8"); for (const m of xml.matchAll(/([^<]+)<\/loc>/g)) urls.push(m[1].trim()); } return urls; } async function submit(endpoint, key, urls) { const res = await fetch(endpoint, { method: "POST", headers: { "Content-Type": "application/json; charset=utf-8" }, body: JSON.stringify({ host: HOST, key, keyLocation: `https://${HOST}/${key}.txt`, urlList: urls, }), }); return `${endpoint} -> ${res.status} ${res.statusText}`; } const key = findKey(); const urls = collectUrls(); console.log(`IndexNow: key=${key} / urls=${urls.length}`); for (const ep of [ "https://api.indexnow.org/indexnow", "https://www.bing.com/indexnow", ]) { try { console.log(" ", await submit(ep, key, urls)); } catch (e) { console.error(` ${ep} FAILED:`, e.message); } }