forked from Mike/freno-dev
FRE-1670: publish /terms and the support address on the Nessa site
nessa.freno.me/terms was a live 404 although AppSettings.termsOfServiceURL links it from Settings > Legal and the paywall. The document existed only on an unmerged branch and had no host-dispatch route, so it could not serve on the subdomain. Carry the Terms of Use page, add the /terms dispatcher, and publish nessa-support@freno.me on terms, privacy, contact and deletion. - src/routes/terms.tsx: host-aware dispatch for nessa; other sites 404. - src/routes/nessa/terms.tsx: the Terms page; its contact section names the support address. - privacy: add the controller clause and the support address. - contact/deletion: show the support address; deletion also accepts a request by email. - subdomain-dispatch.test.ts: list directories before filtering to .tsx files. The old predicate only ever received file names, so it asserted over an empty list and missed the missing /terms dispatch. - support-contact.test.ts: guard that every contact route renders the one address the app shows. App side unchanged: termsOfServiceURL stays https://nessa.freno.me/terms.
This commit is contained in:
@@ -14,7 +14,10 @@ import { describe, it, expect } from "bun:test";
|
||||
import { readdirSync, existsSync, statSync } from "fs";
|
||||
|
||||
function isRouteFile(name: string): boolean {
|
||||
return name.endsWith(".tsx") || name.endsWith(".ts");
|
||||
// Page routes are components; the `.ts` files beside them are pure content /
|
||||
// metadata modules (content.ts, meta.ts, *-content.ts) with no default
|
||||
// export the router can render, so they are not dispatch targets.
|
||||
return name.endsWith(".tsx");
|
||||
}
|
||||
|
||||
function listRouteFiles(dir: string): string[] {
|
||||
@@ -25,6 +28,20 @@ function listRouteFiles(dir: string): string[] {
|
||||
}
|
||||
}
|
||||
|
||||
function listDirectories(dir: string): string[] {
|
||||
try {
|
||||
return readdirSync(dir).filter((name) => {
|
||||
try {
|
||||
return statSync(`${dir}/${name}`).isDirectory();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function hasDispatchRoute(routeName: string, routesDir: string): boolean {
|
||||
// Check for src/routes/<name>.tsx
|
||||
if (existsSync(`${routesDir}/${routeName}.tsx`)) {
|
||||
@@ -41,14 +58,12 @@ describe("subdomain routing dispatch invariant", () => {
|
||||
const routesDir = "./src/routes";
|
||||
|
||||
it("every subdomain route has a top-level dispatch route", () => {
|
||||
const prefixDirs = listRouteFiles(routesDir)
|
||||
.filter((name) => {
|
||||
try {
|
||||
return statSync(`${routesDir}/${name}`).isDirectory();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
// List directory entries before filtering to route files. The previous
|
||||
// shape filtered with `listRouteFiles` first, which only ever returns
|
||||
// `.tsx`/`.ts` names, so `statSync(...).isDirectory()` was never true
|
||||
// and the assertion ran over an empty list — it passed while `/terms`
|
||||
// had no dispatch file (FRE-1670).
|
||||
const prefixDirs = listDirectories(routesDir)
|
||||
// Exclude non-product subdomains
|
||||
.filter((name) =>
|
||||
["nessa", "lineage", "gaze", "inputhalo", "nook"].includes(name)
|
||||
|
||||
Reference in New Issue
Block a user