78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
import { listSummaries } from '#lib/server/lists.js';
|
|
import { db } from '#lib/server/db/index.js';
|
|
import { blogArticles, bookWorks } from '#lib/server/db/schema/index.js';
|
|
import { SITE_ORIGIN } from '#lib/seo.js';
|
|
import { races } from '#lib/derby/races.js';
|
|
import { COURSES } from '#lib/language-learner/courses/index.js';
|
|
import { eq } from 'drizzle-orm';
|
|
import type { RequestHandler } from './$types';
|
|
|
|
const staticPaths = [
|
|
'/',
|
|
'/projects',
|
|
'/trackers',
|
|
'/blog',
|
|
'/lists',
|
|
'/trackers/books',
|
|
'/projects/game-tracker',
|
|
'/projects/game-tracker/pokemon',
|
|
'/projects/game-tracker/osu',
|
|
'/projects/game-tracker/pokemon/locations',
|
|
'/projects/animaldex',
|
|
'/projects/energy',
|
|
'/projects/derby',
|
|
'/projects/spotify-beatmap-finder',
|
|
'/projects/world-opinions',
|
|
'/projects/language-learner',
|
|
...COURSES.map((c) => `/projects/language-learner/${c.code}`)
|
|
];
|
|
|
|
function escapeXml(value: string): string {
|
|
return value.replace(/[<>&"']/g, (character) => {
|
|
const entities: Record<string, string> = {
|
|
'<': '<',
|
|
'>': '>',
|
|
'&': '&',
|
|
'"': '"',
|
|
"'": '''
|
|
};
|
|
return entities[character];
|
|
});
|
|
}
|
|
|
|
export const GET: RequestHandler = async () => {
|
|
const [articles, lists, books] = await Promise.all([
|
|
db
|
|
.select({ slug: blogArticles.slug, updatedAt: blogArticles.updatedAt })
|
|
.from(blogArticles)
|
|
.where(eq(blogArticles.status, 'published')),
|
|
listSummaries(),
|
|
db.select({ id: bookWorks.id, updatedAt: bookWorks.updatedAt }).from(bookWorks)
|
|
]);
|
|
const entries: { path: string; lastmod?: string }[] = [
|
|
...staticPaths.map((path) => ({ path })),
|
|
...races.map((race) => ({ path: `/projects/derby/${race.slug}` })),
|
|
...articles.map((article) => ({
|
|
path: `/blog/${encodeURIComponent(article.slug)}`,
|
|
lastmod: article.updatedAt.toISOString()
|
|
})),
|
|
...lists.map((list) => ({ path: `/lists/${encodeURIComponent(list.slug)}` })),
|
|
...books.map((book) => ({
|
|
path: `/trackers/books/${book.id}`,
|
|
lastmod: book.updatedAt.toISOString()
|
|
}))
|
|
];
|
|
const body = `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${entries
|
|
.map(
|
|
({ path, lastmod }) =>
|
|
` <url><loc>${escapeXml(new URL(path, SITE_ORIGIN).href)}</loc>${lastmod ? `<lastmod>${lastmod}</lastmod>` : ''}</url>`
|
|
)
|
|
.join('\n')}\n</urlset>\n`;
|
|
return new Response(body, {
|
|
headers: {
|
|
'content-type': 'application/xml; charset=utf-8',
|
|
'cache-control': 'public, max-age=3600'
|
|
}
|
|
});
|
|
};
|