/**
* Reserved Names — single source of truth for route/name collision prevention
*
* All system route prefixes are listed here. Entity names (repos, groups,
* namespaces, usernames) are validated against this list so collisions
* with system routes are architecturally impossible.
*/
export const RESERVED_NAMES = new Set([
// Top-level system routes
'api',
'admin',
'profile',
'search',
'login',
'deploy',
'merge',
'groups',
'join',
// Potential future system routes
'static',
'assets',
'settings',
'help',
'new',
'explore',
'notifications',
// Special characters / separators
'-',
'_'
])
export const NAME_REGEX = /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/
/**
* Validate an entity name (repo, group, namespace, username).
* Must be URL-safe slug: lowercase a-z, 0-9, hyphens. Not reserved.
* @param {string} name
* @returns {{ valid: boolean, error?: string }}
*/
export function validateName (name) {
if (!name || typeof name !== 'string') {
return { valid: false, error: 'Name is required' }
}
if (name.length < 1 || name.length > 64) {
return { valid: false, error: 'Name must be 1-64 characters' }
}
if (!NAME_REGEX.test(name)) {
return { valid: false, error: 'Name must be lowercase alphanumeric with hyphens (no leading/trailing hyphens)' }
}
if (name.includes('--')) {
return { valid: false, error: 'Name must not contain consecutive hyphens' }
}
if (RESERVED_NAMES.has(name)) {
return { valid: false, error: `Name "${name}" is reserved` }
}
return { valid: true }
}