/** * Map an inbound deep link (custom scheme or universal/app link) to an in-app * route for the Next router. * * Conventions: * - Custom scheme: `ulti://go/` -> `/` * `ulti:///` -> `//` * - Universal link: `https:///app//` -> `/` * * The OAuth callback (`ulti://oauth/callback`) is consumed by the native * auth flow and intentionally returns null here. */ export function routeForDeepLink(rawUrl: string): string | null { let u: URL try { u = new URL(rawUrl) } catch { return null } // Custom scheme (e.g. ultimail:, ultidrive:) if (u.protocol.startsWith("ulti") && u.protocol.endsWith(":")) { if (u.hostname === "oauth") return null // handled by native-auth const host = u.hostname const path = u.pathname.replace(/^\/+/, "") let route: string if (host === "go" || host === "") { route = `/${path}` } else { route = `/${host}${path ? `/${path}` : ""}` } return normalize(route, u.search) } // Universal / App link: https://host/app// if (u.protocol === "https:" || u.protocol === "http:") { const parts = u.pathname.split("/").filter(Boolean) const appIdx = parts.indexOf("app") if (appIdx >= 0 && parts.length > appIdx + 1) { const rest = parts.slice(appIdx + 2).join("/") return normalize(`/${rest}`, u.search) } return normalize(u.pathname, u.search) } return null } function normalize(route: string, search: string): string { const cleaned = route.replace(/\/{2,}/g, "/") const path = cleaned === "/" || cleaned === "" ? "/" : cleaned.replace(/\/$/, "") return `${path}${search ?? ""}` }