Beyond parity — the web-feasible versions of the "host-only" items plus extras AtomCMS doesn't have: - App-level abuse/DDoS guard (src/lib/services/abuse-guard.ts): counts requests per IP and auto-adds flooders to website_ip_blacklist (enforced by the access guard) + fires ddosDetected(). OFF by default, tunable via settings. The iptables layer stays host-only; this is the real app-tier mitigation. Access guard now also enforces the IP blacklist (cached). - PWA: a themeable web manifest (src/app/manifest.ts) + a service worker (public/sw.js, cache-first assets / network-first pages) registered after hydration — the hotel is now installable. - /api/health: DB + emulator(RCON) + runtime status probe. - /developers: a public API documentation page covering every REST endpoint with its method, path and auth requirement. - jobs-worker: daily emulator JAR backup (runs host-side in the worker, like AtomCMS's backup command) — copies + prunes; no-ops unless EMULATOR_JAR_PATH + EMULATOR_BACKUP_DIR are set. Verified live (prod, amx_test): /api/health ok, manifest + sw served, docs page renders, normal pages unaffected by the guard. tsc 0, vitest 49/49, next build 0.
24 lines
898 B
TypeScript
24 lines
898 B
TypeScript
import type { MetadataRoute } from "next";
|
|
import { siteSettings } from "@/lib/services/site-settings";
|
|
|
|
// Web app manifest — makes the hotel installable as a PWA (AtomCMS exposed PWA
|
|
// settings but the rewrite ships a real, themeable manifest). Name + theme
|
|
// colour follow the live website_settings; falls back to defaults with no DB.
|
|
export default async function manifest(): Promise<MetadataRoute.Manifest> {
|
|
const name = (await siteSettings.get("hotel_name", "Atom")) ?? "Atom";
|
|
const theme = (await siteSettings.get("color_primary", "#f59e0b")) ?? "#f59e0b";
|
|
|
|
return {
|
|
name,
|
|
short_name: name,
|
|
description: `${name} — a Habbo retro hotel.`,
|
|
start_url: "/",
|
|
display: "standalone",
|
|
background_color: "#0f1117",
|
|
theme_color: theme,
|
|
icons: [
|
|
{ src: "/assets/images/home_icon.gif", sizes: "any", type: "image/gif", purpose: "any" },
|
|
],
|
|
};
|
|
}
|