import { buildUrl, type Route, type RouteParams, routes, type RoutesWithParams, } from "./types/routes.ts"; const APP_BASE = "/app"; type Brand = T & { readonly __brand: B }; type AppPath = Brand; function asAppPath(path: string): AppPath { const normalized = path.startsWith("/") ? path : "/" + path; return normalized as AppPath; } function getAppPath(): AppPath { const pathname = globalThis.location.pathname; if (pathname.startsWith(APP_BASE)) { const path = pathname.slice(APP_BASE.length) || "/"; return asAppPath(path); } return asAppPath("/"); } function getSearchParams(): URLSearchParams { return new URLSearchParams(globalThis.location.search); } interface RouterState { readonly path: AppPath; readonly searchParams: URLSearchParams; } const state = $state<{ current: RouterState }>({ current: { path: getAppPath(), searchParams: getSearchParams(), }, }); function updateState(): void { state.current = { path: getAppPath(), searchParams: getSearchParams(), }; } globalThis.addEventListener("popstate", updateState); export function navigate( route: R, options?: { params?: R extends RoutesWithParams ? RouteParams[R] : never; replace?: boolean; }, ): void { const url = options?.params ? buildUrl(route, options.params) : route; const fullPath = APP_BASE + (url.startsWith("/") ? url : "/" + url); if (options?.replace) { globalThis.history.replaceState(null, "", fullPath); } else { globalThis.history.pushState(null, "", fullPath); } updateState(); } export function getCurrentPath(): AppPath { return state.current.path; } export function getCurrentSearchParams(): URLSearchParams { return state.current.searchParams; } export function getSearchParam(key: string): string | null { return state.current.searchParams.get(key); } export function getFullUrl(path: string): string { return APP_BASE + (path.startsWith("/") ? path : "/" + path); } export function isCurrentRoute(route: Route): boolean { const pathWithoutQuery = state.current.path.split("?")[0]; return pathWithoutQuery === route; } export { type Route, type RouteParams, routes };