121 lines
2.8 KiB
TypeScript
121 lines
2.8 KiB
TypeScript
/**
|
|
* Mode detection system for GridPilot website
|
|
*
|
|
* Controls whether the site shows pre-launch content or alpha platform
|
|
* Based on NEXT_PUBLIC_GRIDPILOT_MODE environment variable
|
|
*/
|
|
|
|
export type AppMode = 'pre-launch' | 'alpha';
|
|
|
|
const VALID_MODES: readonly AppMode[] = ['pre-launch', 'alpha'] as const;
|
|
|
|
/**
|
|
* Get the current application mode from environment variable
|
|
* Defaults to 'pre-launch' if not set or invalid
|
|
*
|
|
* @throws {Error} If mode is set but invalid (development only)
|
|
* @returns {AppMode} The current application mode
|
|
*/
|
|
export function getAppMode(): AppMode {
|
|
const mode = process.env.NEXT_PUBLIC_GRIDPILOT_MODE;
|
|
|
|
if (!mode) {
|
|
return 'pre-launch';
|
|
}
|
|
|
|
if (!isValidMode(mode)) {
|
|
const validModes = VALID_MODES.join(', ');
|
|
const error = `Invalid NEXT_PUBLIC_GRIDPILOT_MODE: "${mode}". Must be one of: ${validModes}`;
|
|
|
|
if (process.env.NODE_ENV === 'development') {
|
|
throw new Error(error);
|
|
}
|
|
|
|
console.error(error);
|
|
return 'pre-launch';
|
|
}
|
|
|
|
return mode;
|
|
}
|
|
|
|
/**
|
|
* Type guard to check if a string is a valid AppMode
|
|
*/
|
|
function isValidMode(mode: string): mode is AppMode {
|
|
return VALID_MODES.includes(mode as AppMode);
|
|
}
|
|
|
|
/**
|
|
* Check if currently in pre-launch mode
|
|
*/
|
|
export function isPreLaunch(): boolean {
|
|
return getAppMode() === 'pre-launch';
|
|
}
|
|
|
|
/**
|
|
* Check if currently in alpha mode
|
|
*/
|
|
export function isAlpha(): boolean {
|
|
return getAppMode() === 'alpha';
|
|
}
|
|
|
|
/**
|
|
* Get list of public routes that are always accessible
|
|
*/
|
|
export function getPublicRoutes(): readonly string[] {
|
|
return [
|
|
// Core public pages
|
|
'/',
|
|
|
|
// Public content routes (leagues, drivers, teams, leaderboards, races)
|
|
'/leagues',
|
|
'/drivers',
|
|
'/teams',
|
|
'/leaderboards',
|
|
'/races',
|
|
|
|
// Auth routes
|
|
'/api/signup',
|
|
'/api/auth/signup',
|
|
'/api/auth/login',
|
|
'/api/auth/forgot-password',
|
|
'/api/auth/reset-password',
|
|
'/api/auth/demo-login',
|
|
'/api/auth/session',
|
|
'/api/auth/logout',
|
|
'/auth/login',
|
|
'/auth/signup',
|
|
'/auth/forgot-password',
|
|
'/auth/reset-password',
|
|
'/auth/iracing',
|
|
'/auth/iracing/start',
|
|
'/auth/iracing/callback',
|
|
] as const;
|
|
}
|
|
|
|
/**
|
|
* Check if a route is public (accessible in all modes)
|
|
* Supports both exact matches and prefix matches for nested routes
|
|
*/
|
|
export function isPublicRoute(pathname: string): boolean {
|
|
const publicRoutes = getPublicRoutes();
|
|
|
|
// Check exact match first
|
|
if (publicRoutes.includes(pathname)) {
|
|
return true;
|
|
}
|
|
|
|
// Check prefix matches for nested routes
|
|
// e.g., '/leagues' should match '/leagues/123', '/leagues/create', etc.
|
|
const publicPrefixes = [
|
|
'/leagues',
|
|
'/drivers',
|
|
'/teams',
|
|
'/leaderboards',
|
|
'/races',
|
|
];
|
|
|
|
return publicPrefixes.some(prefix =>
|
|
pathname === prefix || pathname.startsWith(prefix + '/')
|
|
);
|
|
} |