Files
chat_web_app/llm-fe/scripts/pingIndexNow.js
T
westfarn 7a8f413483
Deploy Beta / unit-tests (push) Successful in 13s
Unit Tests / test (push) Successful in 13s
Deploy Beta / deploy-beta (push) Successful in 3m50s
Public page SEO and production analytics (#125)
## Summary
- Closes the public-page gaps from #124: each route gets its own title, description, canonical, heading, links, and JSON-LD, and unknown URLs have a real 404 document.
- Adds HeyCatch and the Google tag (`G-V12DLRLPWR`) only on the production site and the iOS and Android apps. Tianji still loads on beta.
- Needs the server-infra change that stops serving the app shell for missing paths.

## Test plan
- [ ] Build production and confirm `/` and `/pricing/` HTML include a unique title, description, canonical, one h1, social tags, related links, and Organization JSON-LD.
- [ ] Confirm a nonsense path is served as `404.html` once the nginx change is deployed.
- [ ] Confirm beta and local web do not load HeyCatch or gtag, and that a production or native build does.
- [ ] Open the live site after deploy and click around, then mark HeyCatch installed in its dashboard.

Reviewed-on: #125
2026-10-19 08:01:44 -07:00

41 lines
1.3 KiB
JavaScript

/**
* One IndexNow POST for the URLs in the sitemap. Run after the prod files are published.
*/
const fs = require('fs');
const path = require('path');
const { INDEXNOW_KEY, indexNowBody, sitemapEntries } = require('./sitemap');
async function pingIndexNow(fetchImpl = fetch, urls) {
const keyPath = path.join(__dirname, '..', 'public', `${INDEXNOW_KEY}.txt`);
const key = fs.readFileSync(keyPath, 'utf8').trim();
if (key !== INDEXNOW_KEY) {
throw new Error(`IndexNow key file does not match ${INDEXNOW_KEY}`);
}
const urlList = urls || sitemapEntries().map((entry) => entry.loc);
const body = indexNowBody(key, urlList);
const response = await fetchImpl('https://api.indexnow.org/indexnow', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const text = await response.text();
if (response.status !== 200 && response.status !== 202) {
throw new Error(`IndexNow ${response.status}: ${text}`);
}
return { status: response.status, body };
}
async function main() {
const result = await pingIndexNow();
process.stdout.write(`IndexNow ${result.status}\n`);
}
module.exports = { pingIndexNow };
if (require.main === module) {
main().catch((error) => {
process.stderr.write(`${error.message}\n`);
process.exit(1);
});
}