const INTERNAL_URL_BASE = 'https://notifications.ghabilee.invalid' const hasControlCharacter = (value: string) => Array.from(value).some((character) => { const code = character.charCodeAt(0) return code <= 31 || code === 127 }) export const NOTIFICATIONS_RETURN_PATH = '/profile/notifications' export const isSafeInternalNavigationPath = (value: string | null | undefined): value is string => { if (!value || !value.startsWith('/') || value.startsWith('//') || value.includes('\\') || hasControlCharacter(value)) { return false } try { return new URL(value, INTERNAL_URL_BASE).origin === INTERNAL_URL_BASE } catch { return false } } export const addReturnTo = (path: string, returnTo: string): string | null => { if (!isSafeInternalNavigationPath(path) || !isSafeInternalNavigationPath(returnTo)) return null const url = new URL(path, INTERNAL_URL_BASE) url.searchParams.set('returnTo', returnTo) return `${url.pathname}${url.search}${url.hash}` } export const buildNotificationActionPath = (actionUrl: string | null | undefined) => actionUrl ? addReturnTo(/^\/bookings\/[^/?#]+(?:[?#]|$)/.test(actionUrl) ? '/my-events' : actionUrl, NOTIFICATIONS_RETURN_PATH) : null export const getSafeReturnTo = (search: string) => { const returnTo = new URLSearchParams(search).get('returnTo') return isSafeInternalNavigationPath(returnTo) ? returnTo : null }