/** * Route name utilities for filtering internal route names. * * Internal names stay active in the runtime manifest for matching and local * reverse() resolution, but they must not leak into public APIs or generated * route maps. */ export const AUTO_GENERATED_ROUTE_PREFIX = "$path_"; export const INTERNAL_INCLUDE_SCOPE_PREFIX = "$prefix_"; const RESERVED_PREFIXES = [ AUTO_GENERATED_ROUTE_PREFIX, INTERNAL_INCLUDE_SCOPE_PREFIX, ] as const; /** * Check if a route name is internal. * Internal names include: * - unnamed path() routes like "$path__health" or "docs.$path__health" * - hidden include scopes like "$prefix_0.index" or "blog.$prefix_1.post" * * User-defined names containing "$" (e.g. "docs.$admin") are valid and must * be preserved. */ export function isAutoGeneratedRouteName(name: string): boolean { return name.split(".").some((segment) => { return ( segment.startsWith(AUTO_GENERATED_ROUTE_PREFIX) || segment.startsWith(INTERNAL_INCLUDE_SCOPE_PREFIX) ); }); } /** * Validate that a user-provided route name does not collide with * reserved internal prefixes. Checks every dot-separated segment, * mirroring the same rule used by isAutoGeneratedRouteName(). * * Throws with a clear message when a reserved prefix is detected. */ export function validateUserRouteName(name: string): void { for (const segment of name.split(".")) { for (const prefix of RESERVED_PREFIXES) { if (segment.startsWith(prefix)) { throw new Error( `Route name "${name}" contains segment "${segment}" which uses reserved internal prefix "${prefix}". ` + `Choose a different name to avoid collision with auto-generated route names.`, ); } } } }