Files
gridpilot.gg/tests/shared/website/WebsiteRouteManager.ts
2026-01-04 00:39:17 +01:00

103 lines
3.9 KiB
TypeScript

import { routes, routeMatchers } from '../../../apps/website/lib/routing/RouteConfig';
import { stableUuidFromSeedKey } from '../../../adapters/bootstrap/racing/SeedIdHelper';
export type RouteAccess = 'public' | 'auth' | 'admin' | 'sponsor';
export type RouteParams = Record<string, string>;
export interface WebsiteRouteDefinition {
pathTemplate: string;
params?: RouteParams;
access: RouteAccess;
expectedPathTemplate?: string;
allowNotFound?: boolean;
}
export class WebsiteRouteManager {
// Generate IDs the same way the seed does for postgres compatibility
private static readonly IDs = {
LEAGUE: stableUuidFromSeedKey('league-1'),
DRIVER: stableUuidFromSeedKey('driver-1'),
TEAM: stableUuidFromSeedKey('team-1'),
RACE: stableUuidFromSeedKey('race-1'),
PROTEST: stableUuidFromSeedKey('protest-1'),
} as const;
public resolvePathTemplate(pathTemplate: string, params: RouteParams = {}): string {
return pathTemplate.replace(/\[([^\]]+)\]/g, (_match, key) => {
const replacement = params[key];
if (!replacement) {
throw new Error(`Missing route param "${key}" for template "${pathTemplate}"`);
}
return replacement;
});
}
public getWebsiteRouteInventory(): WebsiteRouteDefinition[] {
const result: WebsiteRouteDefinition[] = [];
const pushRoute = (pathTemplate: string, params?: RouteParams) => {
result.push({
pathTemplate,
...(params ? { params } : {}),
access: this.getAccessLevel(pathTemplate),
});
};
const processGroup = (groupRoutes: Record<string, string | ((id: string) => string)>) => {
Object.values(groupRoutes).forEach((value) => {
if (typeof value === 'function') {
const template = value(WebsiteRouteManager.IDs.LEAGUE);
pushRoute(template, { id: WebsiteRouteManager.IDs.LEAGUE });
return;
}
pushRoute(value);
});
};
processGroup(routes.auth);
processGroup(routes.public);
processGroup(routes.protected);
processGroup(routes.sponsor);
processGroup(routes.admin);
processGroup(routes.league);
processGroup(routes.race);
processGroup(routes.team);
processGroup(routes.driver);
processGroup(routes.error);
return result.sort((a, b) => a.pathTemplate.localeCompare(b.pathTemplate));
}
public getParamEdgeCases(): WebsiteRouteDefinition[] {
// Use non-existent UUIDs that will trigger 404 responses
const nonExistentId = '00000000-0000-0000-0000-000000000000';
return [
{ pathTemplate: '/races/[id]', params: { id: nonExistentId }, access: 'public', allowNotFound: true },
{ pathTemplate: '/leagues/[id]', params: { id: nonExistentId }, access: 'public', allowNotFound: true },
];
}
public getFaultInjectionRoutes(): WebsiteRouteDefinition[] {
return [
{ pathTemplate: '/leagues/[id]', params: { id: WebsiteRouteManager.IDs.LEAGUE }, access: 'public' },
{ pathTemplate: '/leagues/[id]/schedule/admin', params: { id: WebsiteRouteManager.IDs.LEAGUE }, access: 'admin' },
{ pathTemplate: '/sponsor/dashboard', access: 'sponsor' },
{ pathTemplate: '/races/[id]', params: { id: WebsiteRouteManager.IDs.RACE }, access: 'public' },
];
}
public getAuthDriftRoutes(): WebsiteRouteDefinition[] {
return [{ pathTemplate: '/sponsor/dashboard', access: 'sponsor' }];
}
public getAccessLevel(pathTemplate: string): RouteAccess {
// NOTE: `routeMatchers.isInGroup(path, 'public')` is prefix-based and will treat everything
// as public because the home route is `/`. Use `isPublic()` for correct classification.
if (routeMatchers.isInGroup(pathTemplate, 'admin')) return 'admin';
if (routeMatchers.isInGroup(pathTemplate, 'sponsor')) return 'sponsor';
if (routeMatchers.isPublic(pathTemplate)) return 'public';
if (routeMatchers.requiresAuth(pathTemplate)) return 'auth';
return 'public';
}
}