Now with legal policies and services pages

This commit is contained in:
2026-03-09 17:12:03 -03:00
parent 66640fa535
commit 164ba69010
63 changed files with 3659 additions and 202 deletions

View File

@@ -0,0 +1,99 @@
#!/usr/bin/env node
/**
* Post-build: generate sitemap.xml from prerendered pages in dist/.
* Scans for index.html (root and under each path), excludes 410 paths.
* Run after vite build and critters, before copy-410-paths so 410 dirs don't exist yet.
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { PATHS as PATHS_410 } from './410-paths.mjs';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const DIST = path.join(__dirname, '..', 'dist');
/** Must match src/lib/seo.ts SEO_DEFAULTS.baseUrl */
const BASE_URL = 'https://mifi.ventures';
const EXCLUDE_FILES = new Set(['404.html', '410.html']);
const excludeSet = new Set(PATHS_410);
/**
* adapter-static emits path.html or path/index.html. Walk dist and collect
* every .html that represents a page (exclude 404/410 and 410-gone paths).
*/
function findPages(dir, basePath = '') {
const entries = fs.readdirSync(dir, { withFileTypes: true });
const pages = [];
for (const e of entries) {
const rel = basePath ? `${basePath}/${e.name}` : e.name;
if (e.isDirectory()) {
const indexPath = path.join(dir, e.name, 'index.html');
if (fs.existsSync(indexPath)) {
if (!excludeSet.has(rel)) {
pages.push({ path: rel, indexPath });
}
} else {
pages.push(...findPages(path.join(dir, e.name), rel));
}
} else if (e.name.endsWith('.html') && !EXCLUDE_FILES.has(e.name)) {
const urlPath = e.name === 'index.html'
? basePath
: (basePath ? `${basePath}/${e.name.slice(0, -5)}` : e.name.slice(0, -5));
if (!excludeSet.has(urlPath)) {
pages.push({ path: urlPath, indexPath: path.join(dir, e.name) });
}
}
}
return pages;
}
function escapeXml(s) {
return s
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
}
function main() {
const indexHtml = path.join(DIST, 'index.html');
if (!fs.existsSync(indexHtml)) {
console.error('dist/index.html not found. Run build first.');
process.exit(1);
}
const pages = findPages(DIST).sort((a, b) => {
if (a.path === '') return -1;
if (b.path === '') return 1;
return a.path.localeCompare(b.path);
});
const urlElements = [];
for (const { path: pagePath, indexPath } of pages) {
const loc = pagePath ? `${BASE_URL}/${pagePath}` : BASE_URL;
const stat = fs.statSync(indexPath);
const lastmod = stat.mtime.toISOString().slice(0, 10);
urlElements.push(
` <url>\n <loc>${escapeXml(loc)}</loc>\n <lastmod>${lastmod}</lastmod>\n </url>`
);
}
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urlElements.join('\n')}
</urlset>
`;
fs.writeFileSync(path.join(DIST, 'sitemap.xml'), xml, 'utf8');
console.log('✓ sitemap.xml generated with', pages.length, 'URLs.');
}
main();