@jasonshimmy/custom-elements-runtime 3.1.2 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/custom-elements-runtime.cjs.js +1 -1
- package/dist/custom-elements-runtime.es.js +3 -3
- package/dist/custom-elements-runtime.jit-css.cjs.js +1 -1
- package/dist/custom-elements-runtime.jit-css.es.js +2 -2
- package/dist/custom-elements-runtime.router.cjs.js +14 -14
- package/dist/custom-elements-runtime.router.cjs.js.map +1 -1
- package/dist/custom-elements-runtime.router.es.js +469 -468
- package/dist/custom-elements-runtime.router.es.js.map +1 -1
- package/dist/custom-elements-runtime.ssr-middleware.cjs.js +3 -1
- package/dist/custom-elements-runtime.ssr-middleware.cjs.js.map +1 -1
- package/dist/custom-elements-runtime.ssr-middleware.es.js +44 -42
- package/dist/custom-elements-runtime.ssr-middleware.es.js.map +1 -1
- package/dist/custom-elements-runtime.ssr.cjs.js +2 -2
- package/dist/custom-elements-runtime.ssr.cjs.js.map +1 -1
- package/dist/custom-elements-runtime.ssr.es.js +5 -4
- package/dist/custom-elements-runtime.ssr.es.js.map +1 -1
- package/dist/{hooks-xWZhQHco.js → hooks-BH-CpUun.js} +223 -214
- package/dist/hooks-BH-CpUun.js.map +1 -0
- package/dist/hooks-NOFG9QRQ.cjs +6 -0
- package/dist/hooks-NOFG9QRQ.cjs.map +1 -0
- package/dist/runtime/ssr-context.d.ts +1 -13
- package/dist/runtime/vdom-ssr-dsd.d.ts +14 -0
- package/dist/ssr-middleware.d.ts +18 -2
- package/dist/ssr.d.ts +3 -4
- package/dist/template-compiler-CDvhsHia.cjs +22 -0
- package/dist/template-compiler-CDvhsHia.cjs.map +1 -0
- package/dist/{template-compiler-ZhSg1yPh.js → template-compiler-DiE69FLO.js} +4 -4
- package/dist/template-compiler-DiE69FLO.js.map +1 -0
- package/package.json +1 -1
- package/dist/hooks-x8M4knLc.cjs +0 -6
- package/dist/hooks-x8M4knLc.cjs.map +0 -1
- package/dist/hooks-xWZhQHco.js.map +0 -1
- package/dist/template-compiler-CTUhEHr8.cjs +0 -22
- package/dist/template-compiler-CTUhEHr8.cjs.map +0 -1
- package/dist/template-compiler-ZhSg1yPh.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-elements-runtime.router.es.js","sources":["../src/lib/router/path-utils.ts","../src/lib/router/matcher.ts","../src/lib/router/component-loader.ts","../src/lib/router/active-proxy.ts","../src/lib/router/instance.ts"],"sourcesContent":["// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nexport const DEFAULT_SCROLL_CONFIG = {\n enabled: true,\n offset: 0,\n timeoutMs: 2000,\n} as const;\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Parse URL search string into query parameters object.\n * @param search - The search string (with or without leading '?')\n * @returns Object with query parameter key-value pairs\n */\nexport const parseQuery = (search: string): Record<string, string> => {\n if (!search) return {};\n if (typeof URLSearchParams === 'undefined') return {};\n return Object.fromEntries(new URLSearchParams(search));\n};\n\n/**\n * Serialize query parameters object into URL search string.\n * @param q - Query parameters object\n * @returns Search string with leading '?' or empty string\n */\nexport const serializeQuery = (q: Record<string, string> | undefined) => {\n if (!q || Object.keys(q).length === 0) return '';\n try {\n return '?' + new URLSearchParams(q as Record<string, string>).toString();\n } catch {\n return '';\n }\n};\n\n/**\n * Detect dangerous javascript: URIs to prevent XSS attacks.\n * @param s - URL string to check\n * @returns True if the URL uses a dangerous scheme\n */\nexport const isDangerousScheme = (s: string): boolean => {\n if (!s) return false;\n return /^\\s*javascript\\s*:/i.test(s);\n};\n\n/**\n * Check if a URL is absolute (has protocol or is protocol-relative).\n * @param url - URL string to check\n * @returns True if the URL is absolute\n */\nexport const isAbsoluteUrl = (url: string): boolean => {\n return /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(url) || url.startsWith('//');\n};\n\n/**\n * Safely decode a URI component, returning original value on error.\n * @param value - String to decode\n * @returns Decoded string or original value if decoding fails\n */\nexport const safeDecode = (value: string): string => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n};\n\n/**\n * Normalize a path for consistent route matching.\n * Ensures leading slash, removes trailing slash, and collapses duplicate slashes.\n * @param p - Path string to normalize\n * @returns Normalized path string\n */\nexport function normalizePathForRoute(p: string): string {\n if (!p) return '/';\n // Collapse duplicate slashes, ensure leading slash, remove trailing slash\n let out = p.replace(/\\/+/g, '/');\n if (!out.startsWith('/')) out = '/' + out;\n if (out.length > 1 && out.endsWith('/')) out = out.slice(0, -1);\n return out;\n}\n\n/**\n * Canonicalize base path for consistent handling.\n * @param base - Base path string\n * @returns Canonicalized base path (empty string for root)\n */\nexport const canonicalizeBase = (base: string): string => {\n if (!base) return '';\n const normalized = normalizePathForRoute(base);\n return normalized === '/' ? '' : normalized;\n};\n","import type { Route } from './types';\nimport { safeDecode, normalizePathForRoute } from './path-utils';\nimport { devWarn } from '../runtime/logger';\n\n// Cache compiled route regexes to avoid rebuilding on every navigation.\ntype CompiledRoute =\n | { regex: RegExp; paramNames: string[] }\n | { invalid: true };\nconst compileCache: WeakMap<Route, CompiledRoute> = new WeakMap();\n\nfunction escapeSeg(seg: string) {\n return seg.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction compileRoute(route: Route): CompiledRoute {\n const raw = route.path || '/';\n const routePath = normalizePathForRoute(raw);\n\n const segments =\n routePath === '/' ? [] : routePath.split('/').filter(Boolean);\n\n const paramNames: string[] = [];\n const regexParts: string[] = [];\n\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n\n // Anonymous wildcard\n if (seg === '*') {\n // splat must be terminal\n if (i !== segments.length - 1) {\n devWarn(\n `Route '${route.path}' contains a '*' splat in a non-terminal position; splats must be the last segment. This route will be ignored.`,\n );\n return { invalid: true };\n }\n const name = `splat${paramNames.length}`;\n paramNames.push(name);\n // mark splat token; pattern will be built specially so the\n // preceding slash can be optional (allow empty splat)\n regexParts.push('__SPLAT__');\n continue;\n }\n\n const paramMatch = seg.match(/^:([A-Za-z0-9_-]+)(\\*)?$/);\n if (paramMatch) {\n const name = paramMatch[1];\n const isSplat = !!paramMatch[2];\n // If splat, ensure terminal\n if (isSplat && i !== segments.length - 1) {\n devWarn(\n `Route '${route.path}' contains a splat param ':${name}*' in a non-terminal position; splats must be the last segment. This route will be ignored.`,\n );\n return { invalid: true };\n }\n paramNames.push(name);\n regexParts.push(isSplat ? '__SPLAT__' : '([^/]+)');\n continue;\n }\n\n // Static\n regexParts.push(escapeSeg(seg));\n }\n\n let pattern: string;\n if (regexParts.length === 0) {\n pattern = '^/$';\n } else {\n const last = regexParts[regexParts.length - 1];\n if (last === '__SPLAT__') {\n const prefix = regexParts.slice(0, -1).join('/');\n if (!prefix) {\n // route is like '/:rest*' or '/*' -> allow '/' or '/x' etc.\n pattern = '^(?:/(.*))?(?:/)?$';\n } else {\n pattern = `^/${prefix}(?:/(.*))?(?:/)?$`;\n }\n } else {\n pattern = `^/${regexParts.join('/')}(?:/)?$`;\n }\n }\n try {\n const regex = new RegExp(pattern);\n return { regex, paramNames };\n } catch (e) {\n devWarn(`Failed to compile route regex for '${route.path}': ${String(e)}`);\n return { invalid: true };\n }\n}\n\nexport const matchRoute = (\n routes: Route[],\n path: string,\n): { route: Route | null; params: Record<string, string> } => {\n const incoming = normalizePathForRoute(path);\n\n for (const route of routes) {\n let compiled = compileCache.get(route);\n if (!compiled) {\n compiled = compileRoute(route);\n compileCache.set(route, compiled);\n }\n\n if ((compiled as { invalid?: true }).invalid) continue;\n\n const { regex, paramNames } = compiled as {\n regex: RegExp;\n paramNames: string[];\n };\n const m = regex.exec(incoming);\n if (m) {\n const params: Record<string, string> = {};\n\n for (let i = 0; i < paramNames.length; i++) {\n const rawValue = m[i + 1] || '';\n params[paramNames[i]] = rawValue ? safeDecode(rawValue) : '';\n }\n\n return { route, params };\n }\n }\n\n return { route: null, params: {} };\n};\n\n/**\n * Find the first route that matches the given path.\n * Consolidates repeated inline checks like `routes.find(r => matchRoute([r], path).route !== null)`\n */\nexport function findMatchedRoute(routes: Route[], path: string): Route | null {\n for (const r of routes) {\n if (matchRoute([r], path).route !== null) return r;\n }\n return null;\n}\n\n/**\n * Match routes during server-side rendering.\n *\n * Automatically strips any query string and URL fragment from `path` before\n * matching, so callers can safely pass `req.url` (which may include `?key=val`\n * or `#hash`) without causing a missed match.\n *\n * @example\n * ```ts\n * // Both of these correctly match '/blog/:slug'\n * matchRouteSSR(routes, '/blog/hello');\n * matchRouteSSR(routes, '/blog/hello?ref=email#comments');\n * ```\n */\nexport function matchRouteSSR(routes: Route[], path: string) {\n // Strip query string and fragment so callers can pass req.url directly.\n const pathname = path.split('?')[0].split('#')[0];\n return matchRoute(routes, pathname);\n}\n","import type { Route } from './types';\nimport { devError } from '../runtime/logger';\n\n// Async component loader cache with size limit to prevent memory leaks\nconst MAX_COMPONENT_CACHE_SIZE = 50;\nlet componentCache: Record<\n string,\n {\n component: string | HTMLElement | ((...args: unknown[]) => unknown);\n lastAccessed: number;\n }\n> = {};\n\n// Separate cache for loading promises to prevent race conditions\nlet loadingCache: Record<\n string,\n Promise<string | HTMLElement | ((...args: unknown[]) => unknown)>\n> = {};\n\n/**\n * Clear component cache to prevent memory leaks\n */\nexport function clearComponentCache(): void {\n componentCache = {};\n loadingCache = {};\n}\n\n/**\n * Evict least recently used components when cache exceeds size limit\n */\nfunction evictLRUComponents(): void {\n const entries = Object.entries(componentCache);\n if (entries.length <= MAX_COMPONENT_CACHE_SIZE) return;\n\n // Sort by lastAccessed (oldest first) and remove oldest entries\n const sortedEntries = entries.sort(\n ([, a], [, b]) => a.lastAccessed - b.lastAccessed,\n );\n const toRemove = sortedEntries.slice(\n 0,\n entries.length - MAX_COMPONENT_CACHE_SIZE,\n );\n\n for (const [path] of toRemove) {\n delete componentCache[path];\n }\n}\n\n/**\n * Loads a route's component, supporting both static and async.\n * @param route Route object\n * @returns Promise resolving to the component\n */\nexport async function resolveRouteComponent(\n route: Route,\n): Promise<string | HTMLElement | ((...args: unknown[]) => unknown)> {\n if (route.component) return route.component;\n if (route.load) {\n const cached = componentCache[route.path];\n if (cached) {\n // Update last accessed time for LRU tracking\n cached.lastAccessed = Date.now();\n return cached.component;\n }\n\n // Check if already loading to prevent race conditions\n if (loadingCache[route.path] !== undefined) {\n return loadingCache[route.path];\n }\n\n // In SSR context, we need to handle components synchronously when possible\n const isSSR = typeof window === 'undefined';\n\n try {\n // Create loading promise\n const loadPromise = route\n .load()\n .then((mod) => {\n // Evict old components if cache is full\n evictLRUComponents();\n\n const component = mod.default;\n componentCache[route.path] = {\n component,\n lastAccessed: Date.now(),\n };\n\n // Remove from loading cache\n delete loadingCache[route.path];\n\n return component;\n })\n .catch((err) => {\n // Remove from loading cache on error\n delete loadingCache[route.path];\n const errorMsg = err instanceof Error ? err.message : String(err);\n if (isSSR) {\n // In SSR, surface errors more prominently\n devError(\n `SSR component load failed for route: ${route.path}. ${errorMsg}`,\n );\n }\n throw new Error(\n `Failed to load component for route: ${route.path}. ${errorMsg}`,\n );\n });\n\n // Store loading promise to prevent concurrent loads\n loadingCache[route.path] = loadPromise;\n\n return await loadPromise;\n } catch (err) {\n // More descriptive error with original error details\n const errorMsg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Failed to load component for route: ${route.path}. ${errorMsg}`,\n { cause: err },\n );\n }\n }\n throw new Error(`No component or loader defined for route: ${route.path}`);\n}\n","import type { Router, RouteState, Route } from './types';\nimport { devWarn } from '../runtime/logger';\nimport { flushDOMUpdates } from '../runtime/scheduler';\n\n// Module-level reference to the latest initialized router. Tests and\n// components may rely on re-initializing the router during their setup,\n// so exposing this lets components pick up the most recent instance.\nlet activeRouter: Router | null = null;\n\nexport function setActiveRouter(r: Router | null): void {\n activeRouter = r;\n}\n\nexport function getActiveRouter(): Router | null {\n return activeRouter;\n}\n\n// Proxy that provides a stable API for consumers (components/tests).\n// Subscriptions and method calls are forwarded to the currently active\n// router instance. When `activeRouter` changes (via `initRouter`) the\n// proxy rebinds and forwards updates to its listeners so components do\n// not need to re-register on re-init.\ntype RouterListener = (s: RouteState) => void;\nconst _proxyListeners: Set<RouterListener> = new Set();\nlet _proxyInnerUnsub: (() => void) | null = null;\n\nfunction _rebindProxy() {\n // Unsubscribe previous inner subscription to prevent memory leaks\n if (_proxyInnerUnsub) {\n try {\n _proxyInnerUnsub();\n } catch {\n // Ignore unsubscribe errors\n }\n _proxyInnerUnsub = null;\n }\n\n if (activeRouter) {\n // Subscribe to the new router and forward updates\n try {\n // We'll detect whether the inner subscription invokes synchronously.\n // Some store implementations call subscribers immediately; others\n // don't. To guarantee exactly-one initial delivery we record whether\n // the inner callback ran during subscribe and only emit a manual\n // snapshot when it did not.\n let innerCalledSync = false;\n _proxyInnerUnsub = activeRouter.subscribe((s) => {\n innerCalledSync = true;\n // Forward to listeners, using Set iteration which is safe for concurrent modification\n for (const listener of _proxyListeners) {\n try {\n listener(s);\n } catch {\n /* swallow listener errors */\n }\n }\n });\n\n // Update proxy base to reflect active router\n try {\n activeRouterProxy.base = activeRouter.base;\n } catch {\n /* swallow */\n }\n\n // If the inner subscription did not synchronously invoke, emit a\n // single initial snapshot so listeners that were registered while\n // no active router existed receive the current state exactly once.\n if (!innerCalledSync) {\n const cur = activeRouter.getCurrent();\n for (const listener of _proxyListeners) {\n try {\n listener(cur);\n } catch {\n /* swallow */\n }\n }\n } else {\n // Even if inner subscription called synchronously, ensure all listeners\n // receive the current state immediately to handle router re-initialization\n const cur = activeRouter.getCurrent();\n for (const listener of _proxyListeners) {\n try {\n listener(cur);\n } catch {\n /* swallow */\n }\n }\n }\n\n // After synchronously forwarding the current snapshot to proxy\n // listeners, flush any pending DOM updates in browser environments\n // so callers that immediately inspect the DOM observe the updated\n // rendered state.\n try {\n if (typeof window !== 'undefined') flushDOMUpdates();\n } catch {\n /* swallow */\n }\n } catch {\n _proxyInnerUnsub = null;\n }\n }\n}\n\nexport function rebindProxy(): void {\n _rebindProxy();\n}\n\nexport const activeRouterProxy: Router = {\n store: {\n subscribe(listener: RouterListener) {\n if (activeRouter) return activeRouter.store.subscribe(listener);\n // immediate no-op subscribe - provide safe fallback state\n try {\n listener({ path: '/', params: {}, query: {} });\n } catch {\n /* swallow listener errors */\n }\n return () => {};\n },\n getState() {\n return activeRouter\n ? activeRouter.getCurrent()\n : { path: '/', params: {}, query: {} };\n },\n setState(\n partial:\n | Partial<RouteState>\n | ((prev: RouteState) => Partial<RouteState>),\n ) {\n if (!activeRouter) return;\n try {\n if (typeof partial === 'function') {\n activeRouter.store.setState(\n partial as (prev: RouteState) => Partial<RouteState>,\n );\n } else {\n activeRouter.store.setState(partial as Partial<RouteState>);\n }\n } catch {\n /* swallow */\n }\n },\n },\n subscribe(listener: RouterListener) {\n // Defensive check - ensure listener is a function\n if (typeof listener !== 'function') {\n devWarn('activeRouterProxy.subscribe: listener must be a function');\n return () => {};\n }\n\n // Add the listener to the proxy set\n _proxyListeners.add(listener);\n\n // Ensure we are bound to the active router. If not bound, rebind so\n // the inner subscription will forward updates to `_proxyListeners`.\n if (activeRouter) {\n if (!_proxyInnerUnsub) {\n // Rebind will synchronously forward the current state to all\n // proxy listeners (including the one we just pushed). Don't\n // call the listener again here to avoid double-invocation.\n _rebindProxy();\n } else {\n // Inner subscription already present; deliver a synchronous\n // snapshot only to the newly added listener.\n try {\n const currentState = activeRouter.getCurrent();\n if (currentState) {\n listener(currentState);\n }\n } catch (err) {\n devWarn('activeRouterProxy subscription failed', err);\n }\n }\n } else {\n // No active router yet - provide fallback state\n try {\n listener({ path: '/', params: {}, query: {} });\n } catch (err) {\n devWarn('activeRouterProxy fallback state delivery failed', err);\n }\n }\n\n // Return unsubscribe with additional safety checks\n return () => {\n try {\n _proxyListeners.delete(listener);\n // If no more proxy listeners remain, unsubscribe inner subscription\n // to avoid retaining unused references. It will be rebound on demand.\n if (_proxyListeners.size === 0 && _proxyInnerUnsub) {\n try {\n _proxyInnerUnsub();\n } catch (err) {\n devWarn('activeRouterProxy inner unsubscribe failed', err);\n }\n _proxyInnerUnsub = null;\n }\n } catch (err) {\n devWarn('activeRouterProxy unsubscribe failed', err);\n }\n };\n },\n getCurrent() {\n return activeRouter\n ? activeRouter.getCurrent()\n : { path: '/', params: {}, query: {} };\n },\n async push(path: string) {\n if (!activeRouter) return Promise.resolve();\n return activeRouter.push(path);\n },\n async replace(path: string) {\n if (!activeRouter) return Promise.resolve();\n return activeRouter.replace(path);\n },\n back() {\n if (!activeRouter) return;\n return activeRouter.back();\n },\n matchRoute(path: string) {\n return activeRouter\n ? activeRouter.matchRoute(path)\n : { route: null as Route | null, params: {} };\n },\n resolveRouteComponent(route: Route) {\n return activeRouter\n ? activeRouter.resolveRouteComponent(route)\n : Promise.reject(new Error('No active router'));\n },\n base: '',\n scrollToFragment(frag?: string) {\n return activeRouter\n ? activeRouter.scrollToFragment(frag)\n : Promise.resolve(false);\n },\n destroy() {\n if (activeRouter) activeRouter.destroy();\n },\n};\n","import { html } from '../runtime/template-compiler';\nimport { component } from '../runtime/component';\nimport {\n useProps,\n useOnConnected,\n useOnDisconnected,\n useStyle,\n} from '../runtime/hooks';\nimport { ref, computed } from '../runtime/reactive';\nimport { flushDOMUpdates } from '../runtime/scheduler';\nimport { createStore } from '../store';\nimport { devError, devWarn } from '../runtime/logger';\nimport { match } from '../directives';\nimport type {\n RouteState,\n Route,\n RouterLinkProps,\n RouterConfig,\n Router,\n} from './types';\nimport {\n DEFAULT_SCROLL_CONFIG,\n isDangerousScheme,\n isAbsoluteUrl,\n canonicalizeBase,\n normalizePathForRoute,\n parseQuery,\n serializeQuery,\n} from './path-utils';\nimport { matchRoute, findMatchedRoute } from './matcher';\nimport { clearComponentCache, resolveRouteComponent } from './component-loader';\nimport {\n activeRouterProxy,\n setActiveRouter,\n getActiveRouter,\n rebindProxy,\n} from './active-proxy';\n\nexport function useRouter(config: RouterConfig): Router {\n const { routes, base = '', initialUrl, scrollToFragment = true } = config;\n\n // Canonicalize base so callers and internal logic have a single\n // representation. Normalized base will be '' for root or '/x' (no\n // trailing slash). This prevents accidental double-prefixing like\n // '/app/app/about' and makes startsWith checks reliable.\n const canonicalBase = canonicalizeBase(base);\n\n // Normalize scroll configuration\n const _scrollConfig =\n typeof scrollToFragment === 'boolean'\n ? { ...DEFAULT_SCROLL_CONFIG, enabled: scrollToFragment }\n : { ...DEFAULT_SCROLL_CONFIG, ...scrollToFragment };\n\n // getLocation/initial include an optional `fragment` field in practice.\n let getLocation: () => {\n path: string;\n query: Record<string, string>;\n fragment?: string;\n };\n let initial: {\n path: string;\n query: Record<string, string>;\n fragment?: string;\n };\n let store: ReturnType<typeof createStore<RouteState>>;\n let update: (replace?: boolean) => Promise<void>;\n let push: (path: string) => Promise<void>;\n let replaceFn: (path: string) => Promise<void>;\n let back: () => void;\n let destroyFn: () => void = () => {};\n\n // Track redirects to prevent infinite loops\n const redirectTracker = new Set<string>();\n const MAX_REDIRECT_DEPTH = 10;\n let redirectDepth = 0;\n\n // Run matching route guards/hooks\n const runBeforeEnter = async (\n to: RouteState,\n from: RouteState,\n ): Promise<boolean | string> => {\n const matched = findMatchedRoute(routes, to.path);\n if (!matched || !matched.beforeEnter) return true;\n try {\n const result = await matched.beforeEnter(to, from);\n if (typeof result === 'string') {\n // Check for redirect loops\n const redirectKey = `${to.path}->${result}`;\n if (\n redirectTracker.has(redirectKey) ||\n redirectDepth >= MAX_REDIRECT_DEPTH\n ) {\n devError(`Redirect loop detected: ${redirectKey}`);\n return false;\n }\n return result; // Return redirect path instead of navigating immediately\n }\n return result !== false;\n } catch (err) {\n devError('beforeEnter error', err);\n // Reset store to previous state on guard error to maintain consistency\n try {\n store.setState(from);\n } catch {\n /* swallow setState errors */\n }\n // Always let guard errors bubble up for proper error handling\n throw err;\n }\n };\n\n const runOnEnter = async (\n to: RouteState,\n from: RouteState,\n ): Promise<boolean | string> => {\n const matched = findMatchedRoute(routes, to.path);\n if (!matched || !matched.onEnter) return true;\n try {\n const result = await matched.onEnter(to, from);\n if (typeof result === 'string') {\n // Check for redirect loops\n const redirectKey = `${to.path}->${result}`;\n if (\n redirectTracker.has(redirectKey) ||\n redirectDepth >= MAX_REDIRECT_DEPTH\n ) {\n devError(`Redirect loop detected: ${redirectKey}`);\n return false;\n }\n return result; // Return redirect path instead of navigating immediately\n }\n return result !== false;\n } catch (err) {\n devError('onEnter error', err);\n // Reset store to previous state on guard error to maintain consistency\n try {\n store.setState(from);\n } catch {\n /* swallow setState errors */\n }\n // Always let guard errors bubble up for proper error handling\n throw err;\n }\n };\n\n const runAfterEnter = (to: RouteState, from: RouteState): void => {\n const matched = findMatchedRoute(routes, to.path);\n if (!matched || !matched.afterEnter) return;\n try {\n const result: void | Promise<void> = matched.afterEnter(to, from);\n if (result instanceof Promise) {\n result.catch((err: unknown) => {\n devError('afterEnter async error', err);\n });\n }\n } catch (err) {\n devError('afterEnter error', err);\n }\n };\n\n // Cache for route matching to avoid repeated expensive operations\n const matchCache = new Map<\n string,\n { route: Route | null; params: Record<string, string> }\n >();\n const MATCH_CACHE_SIZE = 100;\n\n const cachedMatchRoute = (path: string) => {\n if (matchCache.has(path)) {\n return matchCache.get(path)!;\n }\n\n const result = matchRoute(routes, path);\n\n // Implement proper LRU by clearing oldest entries when cache is full\n if (matchCache.size >= MATCH_CACHE_SIZE) {\n // Remove oldest 25% of entries to avoid frequent cleanup\n const entriesToRemove = Math.floor(MATCH_CACHE_SIZE * 0.25);\n const keys = Array.from(matchCache.keys());\n for (let i = 0; i < entriesToRemove && i < keys.length; i++) {\n matchCache.delete(keys[i]);\n }\n }\n\n matchCache.set(path, result);\n return result;\n };\n\n // Scroll management with per-promise tracking\n const cleanupScrollState = () => {\n // No global cleanup needed - each promise manages its own lifecycle\n };\n\n async function doScrollToElement(id: string, offset = 0): Promise<boolean> {\n try {\n const element = document.getElementById(id);\n if (!element) {\n return false;\n }\n\n if (offset > 0) {\n try {\n const rect = element.getBoundingClientRect();\n const top = Math.max(0, window.scrollY + rect.top - offset);\n if (typeof window.scrollTo === 'function') {\n window.scrollTo({ top, behavior: 'auto' });\n }\n } catch {\n try {\n element.scrollIntoView();\n } catch {\n return false;\n }\n }\n } else {\n if (typeof element.scrollIntoView === 'function') {\n try {\n element.scrollIntoView({\n behavior: 'auto',\n block: 'start',\n inline: 'nearest',\n });\n } catch {\n try {\n element.scrollIntoView();\n } catch {\n return false;\n }\n }\n }\n }\n return true;\n } catch {\n return false;\n }\n }\n\n // Scroll with per-promise lifecycle management and retry for missing elements\n function startScrollForNavigation(\n id: string,\n offset: number = 0,\n timeoutMs: number = 2000,\n ): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n let resolved = false;\n let timeoutId: number | null = null;\n let rafHandle: number | null = null;\n const startTime = Date.now();\n\n const safeResolve = (value: boolean) => {\n if (resolved) return;\n resolved = true;\n if (timeoutId) clearTimeout(timeoutId);\n // Cancel any pending rAF so orphaned retry loops don't keep firing\n // after the promise has already resolved (e.g. on rapid navigation).\n if (rafHandle !== null) cancelAnimationFrame(rafHandle);\n resolve(value);\n };\n\n const attemptScroll = async () => {\n if (resolved) return;\n\n try {\n // Try immediate scroll first\n if (await doScrollToElement(id, offset)) {\n return safeResolve(true);\n }\n\n // For missing elements, continue retrying until timeout\n const retryScroll = async () => {\n if (resolved) return;\n\n const elapsed = Date.now() - startTime;\n if (elapsed >= timeoutMs) {\n return safeResolve(false);\n }\n\n try {\n if (await doScrollToElement(id, offset)) {\n return safeResolve(true);\n }\n\n rafHandle = requestAnimationFrame(retryScroll);\n } catch (error) {\n devWarn('Scroll retry attempt failed:', error);\n rafHandle = requestAnimationFrame(retryScroll);\n }\n };\n\n // Start retry loop after initial attempt\n rafHandle = requestAnimationFrame(retryScroll);\n } catch (error) {\n devWarn('Initial scroll attempt failed:', error);\n safeResolve(false);\n }\n };\n\n // Set timeout as final safety net\n timeoutId = setTimeout(() => {\n safeResolve(false);\n }, timeoutMs);\n\n // Start the attempt immediately with error handling\n attemptScroll().catch((error) => {\n devWarn('Scroll attempt failed:', error);\n safeResolve(false);\n });\n });\n }\n\n // Navigation lock to prevent concurrent navigation race conditions\n let isNavigating = false;\n\n const navigate = async (path: string, replace = false): Promise<void> => {\n // Prevent concurrent navigation\n if (isNavigating) {\n devWarn(`Navigation to ${path} blocked - navigation already in progress`);\n return;\n }\n\n isNavigating = true;\n redirectDepth = 0;\n redirectTracker.clear();\n\n try {\n await performNavigation(path, replace);\n } finally {\n isNavigating = false;\n redirectDepth = 0;\n redirectTracker.clear();\n }\n };\n\n // Extract path parsing logic for reuse in SSR\n const parseNavigationPath = (path: string) => {\n const hashIndex = path.indexOf('#');\n const fragment = hashIndex >= 0 ? path.slice(hashIndex + 1) : '';\n const rawPath = hashIndex >= 0 ? path.slice(0, hashIndex) : path;\n const qIndex = rawPath.indexOf('?');\n const pathBeforeQuery = qIndex >= 0 ? rawPath.slice(0, qIndex) : rawPath;\n const query = qIndex >= 0 ? parseQuery(rawPath.slice(qIndex)) : {};\n const stripped = pathBeforeQuery.startsWith(canonicalBase)\n ? pathBeforeQuery.slice(canonicalBase.length)\n : pathBeforeQuery;\n const normalized = normalizePathForRoute(stripped || '/');\n return {\n path: normalized,\n query,\n fragment,\n };\n };\n\n const performNavigation = async (\n path: string,\n replace = false,\n ): Promise<void> => {\n try {\n const loc = parseNavigationPath(path);\n const match = cachedMatchRoute(loc.path);\n if (!match.route) throw new Error(`No route found for ${loc.path}`);\n\n const from = store.getState();\n const to: RouteState = {\n path: loc.path,\n params: match.params,\n query: loc.query,\n fragment: (loc as { fragment?: string }).fragment,\n };\n\n // beforeEnter guard\n const beforeEnterResult = await runBeforeEnter(to, from);\n if (beforeEnterResult === false) return;\n if (typeof beforeEnterResult === 'string') {\n // Handle redirect\n redirectDepth++;\n const redirectKey = `${to.path}->${beforeEnterResult}`;\n redirectTracker.add(redirectKey);\n await performNavigation(beforeEnterResult, true);\n return;\n }\n\n // onEnter guard (right before commit)\n const onEnterResult = await runOnEnter(to, from);\n if (onEnterResult === false) return;\n if (typeof onEnterResult === 'string') {\n // Handle redirect\n redirectDepth++;\n const redirectKey = `${to.path}->${onEnterResult}`;\n redirectTracker.add(redirectKey);\n await performNavigation(onEnterResult, true);\n return;\n }\n\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n const qstr = serializeQuery(loc.query);\n const href =\n canonicalBase +\n loc.path +\n (qstr || '') +\n (loc.fragment ? '#' + loc.fragment : '');\n if (replace) {\n window.history.replaceState({}, '', href);\n } else {\n window.history.pushState({}, '', href);\n }\n }\n\n store.setState(to);\n\n // afterEnter hook (post commit)\n runAfterEnter(to, from);\n\n // If there's a fragment (hash) preserve it on the URL and attempt to\n // scroll to the element with that id on client-side navigation.\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n try {\n const frag = (to as { fragment?: string }).fragment;\n if (_scrollConfig.enabled && frag) {\n // Start the robust scroll flow (observer + timeout + cancellation)\n startScrollForNavigation(\n String(frag),\n _scrollConfig.offset,\n _scrollConfig.timeoutMs,\n ).catch(() => {});\n }\n } catch {\n /* swallow */\n }\n }\n } catch (err) {\n devError('Navigation error:', err);\n\n // If this is a guard error, re-throw it so the promise rejects properly\n if (\n err instanceof Error &&\n (err.stack?.includes('runBeforeEnter') ||\n err.stack?.includes('runOnEnter'))\n ) {\n throw err;\n }\n\n // For other navigation errors, ensure store state remains consistent\n try {\n const current = store.getState();\n const targetMatches = matchRoute(routes, current.path);\n if (!targetMatches.route) {\n // If current state is invalid, reset to a valid route or root\n let fallbackRoute = routes.find((r) => r.path === '/');\n if (!fallbackRoute) {\n // Find any route that doesn't have dynamic segments as fallback\n fallbackRoute = routes.find(\n (r) => !r.path.includes(':') && !r.path.includes('*'),\n );\n }\n if (!fallbackRoute && routes.length > 0) {\n fallbackRoute = routes[0];\n }\n\n if (fallbackRoute) {\n const fallbackMatch = matchRoute(routes, fallbackRoute.path);\n store.setState({\n path: fallbackRoute.path,\n params: fallbackMatch.params,\n query: {},\n });\n } else {\n devError('No fallback route available for error recovery');\n }\n }\n } catch (recoveryError) {\n devWarn(\n 'State recovery failed during navigation error:',\n recoveryError,\n );\n }\n }\n };\n\n // Validate routes configuration\n const validateRoutes = (routeList: Route[]): boolean => {\n if (!routeList || routeList.length === 0) {\n devError('Router configuration error: No routes provided');\n return false;\n }\n\n const pathSet = new Set<string>();\n for (const route of routeList) {\n if (!route.path) {\n devError('Router configuration error: Route missing path', route);\n return false;\n }\n\n if (pathSet.has(route.path)) {\n devWarn(`Duplicate route path detected: ${route.path}`);\n }\n pathSet.add(route.path);\n\n if (!route.component && !route.load) {\n devWarn(`Route '${route.path}' has no component or load function`);\n }\n }\n return true;\n };\n\n // Validate configuration before proceeding (non-fatal for compatibility)\n validateRoutes(routes);\n\n // Pre-compile all routes for better SSR performance\n const isSSRMode =\n typeof window === 'undefined' || typeof initialUrl !== 'undefined';\n if (isSSRMode) {\n for (const route of routes) {\n // Force compilation of all routes during SSR initialization\n cachedMatchRoute(route.path);\n }\n devWarn(`Pre-compiled ${routes.length} routes for SSR`);\n }\n\n // If an explicit `initialUrl` is provided we treat this as SSR/static rendering\n // even if a `window` exists (useful for hydration tests). Browser mode only\n // applies when `initialUrl` is undefined.\n if (\n typeof window !== 'undefined' &&\n typeof document !== 'undefined' &&\n typeof initialUrl === 'undefined'\n ) {\n // Browser mode\n getLocation = () => {\n try {\n const url = new URL(window.location.href);\n const raw = url.pathname;\n const stripped = raw.startsWith(canonicalBase)\n ? raw.slice(canonicalBase.length)\n : raw;\n const path = normalizePathForRoute(stripped || '/');\n const query = parseQuery(url.search);\n const fragment = url.hash && url.hash.length ? url.hash.slice(1) : '';\n return { path, query, fragment };\n } catch (error) {\n devWarn('Invalid URL detected, falling back to safe defaults', error);\n return { path: '/', query: {}, fragment: '' };\n }\n };\n\n initial = getLocation();\n const match = cachedMatchRoute(initial.path);\n store = createStore<RouteState>({\n path: initial.path,\n params: match.params,\n query: initial.query,\n fragment: (initial as { fragment?: string }).fragment,\n });\n\n update = async (replace = false) => {\n const loc = getLocation();\n await navigate(loc.path, replace);\n };\n\n const handlePopState = () => update(true);\n window.addEventListener('popstate', handlePopState);\n destroyFn = () => window.removeEventListener('popstate', handlePopState);\n\n push = (path: string) => navigate(path, false);\n replaceFn = (path: string) => navigate(path, true);\n back = () => window.history.back();\n\n // Run initial navigation through the guard pipeline so beforeEnter guards\n // fire on the entry URL (e.g. protected routes redirect on hard refresh).\n // queueMicrotask defers until after setActiveRouter()/rebindProxy() complete,\n // ensuring subscribers are bound before the navigation state updates.\n queueMicrotask(() => {\n navigate(initial.path, true).catch((err) => {\n devError('Initial navigation error:', err);\n });\n });\n } else {\n // SSR mode\n getLocation = () => {\n try {\n const url = new URL(initialUrl || '/', 'http://localhost');\n const raw = url.pathname;\n const stripped = raw.startsWith(canonicalBase)\n ? raw.slice(canonicalBase.length)\n : raw;\n const path = normalizePathForRoute(stripped || '/');\n const query = parseQuery(url.search);\n const fragment = url.hash && url.hash.length ? url.hash.slice(1) : '';\n return { path, query, fragment };\n } catch (error) {\n devWarn(\n 'Invalid SSR URL detected, falling back to safe defaults',\n error,\n );\n return { path: '/', query: {}, fragment: '' };\n }\n };\n\n initial = getLocation();\n const match = cachedMatchRoute(initial.path);\n store = createStore<RouteState>({\n path: initial.path,\n params: match.params,\n query: initial.query,\n fragment: (initial as { fragment?: string }).fragment,\n });\n\n update = async () => {\n const loc = getLocation();\n await navigateSSR(loc.path);\n };\n\n // SSR navigation contract:\n // - `push` / `replace` call into `navigateSSR` and return a Promise.\n // - On the server we intentionally surface navigation failures so\n // server-side logic (or tests) can react: missing routes or thrown\n // errors from `beforeEnter`/`onEnter` will cause the Promise to\n // reject. This lets the server render 404s or abort builds.\n // - For valid routes the server-side navigation resolves and updates\n // the internal store state so rendered output matches the target\n // path. The `back()` operation is client-only and is a synchronous\n // no-op in SSR mode.\n const navigateSSR = async (path: string) => {\n // Prevent infinite recursion in SSR mode\n redirectDepth++;\n if (redirectDepth > MAX_REDIRECT_DEPTH) {\n devError(`SSR redirect depth exceeded for path: ${path}`);\n return;\n }\n\n try {\n const loc = parseNavigationPath(path);\n const match = cachedMatchRoute(loc.path);\n // In SSR mode we intentionally surface navigation errors (missing\n // route) to the caller so server-side logic may handle them. If no\n // route matches, throw and let the caller observe the rejection.\n if (!match.route) throw new Error(`No route found for ${loc.path}`);\n\n const from = store.getState();\n const to: RouteState = {\n path: loc.path,\n params: match.params,\n query: loc.query,\n fragment: (loc as { fragment?: string }).fragment,\n };\n\n // beforeEnter guard with redirect tracking - let errors bubble up in SSR\n const matched = findMatchedRoute(routes, to.path);\n if (matched?.beforeEnter) {\n const result = await matched.beforeEnter(to, from);\n if (typeof result === 'string') {\n // Handle redirect with tracking\n const redirectKey = `${to.path}->${result}`;\n redirectTracker.add(redirectKey);\n await navigateSSR(result);\n return;\n }\n if (result === false) return;\n }\n\n // onEnter guard with redirect tracking - let errors bubble up in SSR\n if (matched?.onEnter) {\n const result = await matched.onEnter(to, from);\n if (typeof result === 'string') {\n // Handle redirect with tracking\n const redirectKey = `${to.path}->${result}`;\n redirectTracker.add(redirectKey);\n await navigateSSR(result);\n return;\n }\n if (result === false) return;\n }\n\n store.setState(to);\n\n // afterEnter hook\n if (matched?.afterEnter) {\n matched.afterEnter(to, from);\n }\n } catch (err) {\n // Surface SSR navigation errors so callers (and tests) can observe\n // failures during server-side resolution.\n devError('SSR navigation error:', err);\n throw err;\n }\n };\n\n push = async (path: string) => {\n redirectDepth = 0;\n redirectTracker.clear();\n return navigateSSR(path);\n };\n replaceFn = async (path: string) => {\n redirectDepth = 0;\n redirectTracker.clear();\n return navigateSSR(path);\n };\n back = () => {};\n }\n\n const router: Router = {\n _cleanupScrollState: cleanupScrollState,\n destroy: destroyFn,\n store,\n push,\n replace: replaceFn,\n back,\n subscribe: store.subscribe,\n matchRoute: (path: string) => cachedMatchRoute(path),\n getCurrent: (): RouteState => store.getState(),\n resolveRouteComponent,\n base: canonicalBase,\n // Public API: allow components or tests to explicitly request scrolling to\n // a fragment when they know their DOM is ready. Returns true if scrolled.\n scrollToFragment: (frag?: string) => {\n const id = frag || (store.getState() as RouteState).fragment;\n if (!id) return Promise.resolve(false);\n if (typeof window === 'undefined' || typeof document === 'undefined')\n return Promise.resolve(false);\n return startScrollForNavigation(\n id,\n _scrollConfig.offset,\n _scrollConfig.timeoutMs,\n );\n },\n };\n\n return router;\n}\n\n/**\n * Singleton router instance for global access.\n *\n * Define here to prevent circular dependency\n * issue with component.\n */\n\nexport function initRouter(config: RouterConfig): Router {\n // Clear component cache on reinitialization to prevent stale components\n clearComponentCache();\n\n const router = useRouter(config);\n\n // Clean up previous router instance to prevent listener accumulation\n const prevRouter = getActiveRouter();\n if (prevRouter) {\n try {\n prevRouter.destroy();\n } catch {\n // Ignore cleanup errors - function may not exist in older instances\n }\n try {\n prevRouter._cleanupScrollState?.();\n } catch {\n // Ignore cleanup errors - function may not exist in older instances\n }\n }\n // Expose the most recently initialized router to components defined\n // earlier in the process (tests may call initRouter multiple times).\n // Components reference `activeRouterProxy` so re-calling initRouter updates\n // the router instance they use.\n setActiveRouter(router);\n // Rebind the proxy so any existing subscribers are forwarded to the\n // newly initialized router immediately.\n try {\n rebindProxy();\n try {\n // Only attempt to flush DOM updates in browser environments.\n if (typeof window !== 'undefined') flushDOMUpdates();\n } catch {\n // Ignore DOM flush errors\n }\n\n // Additional flush after rebind to ensure all router-link components\n // have updated their active states before any synchronous inspection\n try {\n if (typeof window !== 'undefined') {\n // Use a microtask to allow reactive computations to complete\n queueMicrotask(() => {\n try {\n flushDOMUpdates();\n } catch {\n /* swallow */\n }\n });\n }\n } catch {\n /* swallow */\n }\n } catch {\n // Ignore proxy rebind errors\n }\n\n component('router-view', async () => {\n // Prefer the latest initialized router (tests may re-init). Resolve the\n // router lazily so components connect to whichever router is currently\n // active instead of capturing a stale instance at definition time.\n // Reactive current route so the component re-renders when router updates\n if (!getActiveRouter()) return html`<div>Router not initialized.</div>`;\n\n const current = ref(activeRouterProxy.getCurrent());\n const isSSR = typeof window === 'undefined';\n\n // We'll capture the unsubscribe function when the component connects\n // and register a disconnect cleanup during render-time (useOnDisconnected\n // must be called during the component render/execution).\n let unsubRouterView: (() => void) | undefined;\n\n // Only set up subscriptions in browser environment\n if (!isSSR) {\n useOnConnected(() => {\n try {\n if (typeof activeRouterProxy.subscribe === 'function') {\n unsubRouterView = activeRouterProxy.subscribe((s) => {\n try {\n // Validate state before updating to prevent corruption\n if (s && typeof s === 'object' && typeof s.path === 'string') {\n current.value = s;\n } else {\n devWarn('router-view received invalid state', s);\n // Fallback to safe default state\n current.value = { path: '/', params: {}, query: {} };\n }\n } catch (e) {\n devWarn('router-view subscription update failed', e);\n // Attempt to recover with safe state\n try {\n current.value = { path: '/', params: {}, query: {} };\n } catch {\n /* swallow recovery errors */\n }\n }\n });\n }\n } catch (e) {\n devWarn('router-view subscribe failed', e);\n }\n });\n\n useOnDisconnected(() => {\n if (typeof unsubRouterView === 'function') {\n try {\n unsubRouterView();\n } catch (e) {\n devWarn('router-view unsubscribe failed', e);\n }\n unsubRouterView = undefined; // Clear reference to prevent memory leaks\n }\n });\n }\n\n const match = activeRouterProxy.matchRoute(current.value.path);\n if (!match || !match.route) return html`<div>Not found</div>`;\n\n // Resolve the component (supports cached async loaders)\n try {\n const compRaw = await activeRouterProxy.resolveRouteComponent(\n match.route!,\n );\n const comp = compRaw as\n | string\n | HTMLElement\n | ((...args: unknown[]) => unknown)\n | undefined;\n // String tag (custom element) -> render as VNode\n if (typeof comp === 'string') {\n return { tag: comp, props: {}, children: [] };\n }\n\n // Function component (sync or async) -> call and return its VNode(s)\n if (typeof comp === 'function') {\n const out = comp();\n const resolved = out instanceof Promise ? out : Promise.resolve(out);\n return resolved.then((resolvedComp) => {\n if (typeof resolvedComp === 'string')\n return { tag: resolvedComp, props: {}, children: [] };\n return resolvedComp;\n });\n }\n\n return html`<div>Invalid route component</div>`;\n } catch {\n return html`<div>Invalid route component</div>`;\n }\n });\n\n component('router-link', () => {\n // Declare props via useProps so observedAttributes are correct\n const props = useProps<Partial<RouterLinkProps>>({\n to: '',\n tag: 'a',\n replace: false,\n exact: false,\n activeClass: 'active',\n exactActiveClass: 'exact-active',\n ariaCurrentValue: 'page',\n disabled: false,\n external: false,\n // allow host `class` and `style` attributes to be read via useProps\n class: '',\n style: '',\n });\n\n const isSSR = typeof window === 'undefined';\n const current = ref(activeRouterProxy.getCurrent());\n\n // For SSR, compute stable active states to prevent hydration mismatches\n const stableCurrentPath = current.value?.path || '/';\n const targetPath = String(props.to || '');\n\n // Pre-compute SSR-safe active states\n const ssrActiveStates = isSSR\n ? {\n isExactActive: computeExactActive(\n stableCurrentPath,\n targetPath,\n activeRouterProxy.base,\n ),\n isActive: computeActive(\n stableCurrentPath,\n targetPath,\n activeRouterProxy.base,\n ),\n isExternal: isAbsoluteUrl(targetPath) || !!props.external,\n }\n : null;\n\n let unsubRouterLink: (() => void) | undefined;\n\n // Keep a minimal internal host-scoped style for element display.\n // Host `style` will be applied to the inner anchor/button element.\n useStyle(() => `a,button{display:inline-block;}`);\n\n // We capture host attributes at connection time and migrate them to\n // internal refs so we can remove them from the host. This prevents\n // global/author CSS targeting the host from styling the host element\n // itself while still allowing authors to use `class`/`style` on the\n // router-link to style the inner anchor/button.\n const hostClassRef = ref((props.class as string) || '');\n const hostStyleRef = ref((props.style as string) || '');\n\n // Only set up DOM interactions in browser environment\n if (!isSSR) {\n let syncCheckInterval: ReturnType<typeof setInterval> | null = null;\n\n useOnConnected((ctx?: unknown) => {\n try {\n if (typeof activeRouterProxy.subscribe === 'function') {\n unsubRouterLink = activeRouterProxy.subscribe((s) => {\n try {\n // Validate state before updating to prevent corruption\n if (s && typeof s === 'object' && typeof s.path === 'string') {\n current.value = s;\n } else {\n devWarn('router-link received invalid state', s);\n // Fallback to safe default state\n current.value = { path: '/', params: {}, query: {} };\n }\n } catch (e) {\n devWarn('router-link subscription update failed', e);\n // Attempt to recover with safe state\n try {\n current.value = { path: '/', params: {}, query: {} };\n } catch {\n /* swallow recovery errors */\n }\n }\n });\n\n // Immediately sync current state after subscription to ensure\n // correct active state even if router was initialized after component creation\n try {\n const currentState = activeRouterProxy.getCurrent();\n if (currentState && typeof currentState.path === 'string') {\n current.value = currentState;\n }\n } catch (e) {\n devWarn('router-link initial state sync failed', e);\n }\n\n // Set up periodic sync check to ensure state accuracy after router changes\n // This catches edge cases where subscription updates might be missed\n syncCheckInterval = setInterval(() => {\n try {\n const latestState = activeRouterProxy.getCurrent();\n if (latestState && typeof latestState.path === 'string') {\n // Only update if state actually changed to avoid unnecessary re-renders\n if (\n JSON.stringify(current.value) !==\n JSON.stringify(latestState)\n ) {\n current.value = latestState;\n }\n }\n } catch {\n // Silent failure - don't spam console with periodic check errors\n }\n }, 100); // Check every 100ms\n }\n } catch (e) {\n devWarn('router-link subscribe failed', e);\n }\n\n // Migrate host `class`/`style` into internal refs and remove them\n // from the host so only the inner element is styled.\n try {\n const host = (ctx as { _host?: HTMLElement } | undefined)?._host;\n if (host instanceof HTMLElement) {\n const hc = host.getAttribute('class');\n const hs = host.getAttribute('style');\n if (hc) hostClassRef.value = hc;\n if (hs) hostStyleRef.value = hs;\n // Remove attributes from host to avoid styling the host\n if (hc !== null) host.removeAttribute('class');\n if (hs !== null) host.removeAttribute('style');\n // Re-render to ensure migrated host classes/styles are applied\n // to the internal anchor/button element.\n try {\n // The `ctx` passed into useOnConnected is the component context\n // which exposes `_requestRender`. Call that to re-render after\n // migrating host attributes into internal refs.\n (\n ctx as unknown as { _requestRender?: () => void }\n )?._requestRender?.();\n // Ensure DOM updates from the scheduled render are flushed so\n // callers (and tests) can synchronously observe migrated\n // classes/styles on the inner anchor/button.\n try {\n flushDOMUpdates();\n } catch {\n /* ignore */\n }\n } catch {\n /* ignore */\n }\n }\n } catch (e) {\n devWarn('router-link host migration failed', e);\n }\n });\n\n useOnDisconnected(() => {\n // Clean up router subscription\n if (typeof unsubRouterLink === 'function') {\n try {\n unsubRouterLink();\n } catch (e) {\n devWarn('router-link unsubscribe failed', e);\n } finally {\n unsubRouterLink = undefined; // Clear reference to prevent memory leaks\n }\n }\n\n // Clean up sync check interval\n if (syncCheckInterval) {\n try {\n clearInterval(syncCheckInterval);\n } catch (e) {\n devWarn('router-link sync interval cleanup failed', e);\n } finally {\n syncCheckInterval = null;\n }\n }\n });\n }\n\n // Use pre-computed values for SSR or dynamic computed for client\n const isExactActive = computed(() => {\n if (isSSR && ssrActiveStates) {\n return ssrActiveStates.isExactActive;\n }\n\n try {\n const runtimeBase = activeRouterProxy.base ?? '';\n const targetRaw = (props.to as string) || '';\n\n // Defensive check for current value\n if (!current.value || typeof current.value.path !== 'string') {\n return false;\n }\n\n return computeExactActive(current.value.path, targetRaw, runtimeBase);\n } catch (err) {\n devWarn('isExactActive computation error', err);\n return false;\n }\n });\n\n const isActive = computed(() => {\n if (isSSR && ssrActiveStates) {\n return ssrActiveStates.isActive;\n }\n\n try {\n const runtimeBase = activeRouterProxy.base ?? '';\n const targetRaw = (props.to as string) || '';\n\n // Defensive check for current value\n if (!current.value || typeof current.value.path !== 'string') {\n return false;\n }\n\n if (props.exact) return isExactActive.value;\n return computeActive(current.value.path, targetRaw, runtimeBase);\n } catch (err) {\n devWarn('isActive computation error', err);\n return false;\n }\n });\n\n // Compute a normalized href for the inner anchor so middle-click / open-in-new-tab\n // uses a canonical absolute path (includes base and fragment). We keep using\n // props.to for router navigation so current behavior (literal `to`) remains.\n const hrefTarget = computed(() => {\n const raw = String(props.to || '');\n // Block obviously dangerous javascript: URIs from becoming clickable\n // hrefs. See isDangerousScheme for rationale.\n if (isDangerousScheme(raw)) return null;\n\n // Preserve absolute URLs with a scheme (http:, mailto:, data:, etc.)\n // and protocol-relative URLs that begin with `//`.\n if (isAbsoluteUrl(raw)) return raw;\n\n // Split fragment and query explicitly so both are preserved.\n const [pathWithQuery, frag] = raw.split('#');\n const [pathOnly, query] = (pathWithQuery || '').split('?');\n\n // Read base dynamically from the current router instance so repeated\n // calls to initRouter (tests) do not leave a stale captured value.\n const runtimeBase = activeRouterProxy.base ?? '';\n // If the provided path already contains the runtime base, strip it to\n // avoid duplicating e.g. '/app/app/about'. Keep a fallback of '/'.\n // Use more robust base removal that handles normalization edge cases.\n let candidate = pathOnly || '/';\n if (runtimeBase && runtimeBase !== '/') {\n // Normalize both base and candidate to ensure consistent comparison\n const normalizedBase = normalizePathForRoute(runtimeBase);\n const normalizedCandidate = normalizePathForRoute(candidate);\n if (normalizedCandidate.startsWith(normalizedBase)) {\n candidate = normalizedCandidate.slice(normalizedBase.length) || '/';\n } else {\n candidate = normalizedCandidate;\n }\n }\n const norm = normalizePathForRoute(candidate || '/');\n return (\n runtimeBase +\n norm +\n (query ? '?' + query : '') +\n (frag ? '#' + frag : '')\n );\n });\n\n // Build user classes reactively from the host `class` attribute prop.\n // We intentionally apply classes to the inner element so the consumer\n // can style the link via `class=\"...\"`.\n const userClasses = computed(() => {\n const rawHost =\n (hostClassRef && hostClassRef.value) || (props.class as string) || '';\n const list = rawHost.split(/\\s+/).filter(Boolean);\n const map: Record<string, boolean> = {};\n for (const c of list) map[c] = true;\n return map;\n });\n\n const classObject = computed(() => ({\n ...userClasses.value,\n [(props.activeClass as string) || 'active']: isActive.value,\n [(props.exactActiveClass as string) || 'exact-active']:\n isExactActive.value,\n }));\n\n // Compute a final class string (template accepts object or string; we\n // convert to string to safely include host classes and conditionals).\n const classString = computed(() =>\n Object.keys(classObject.value)\n .filter((k) => classObject.value[k])\n .join(' '),\n );\n\n const tagName = computed(() => (props.tag as string) || 'a');\n const isButton = computed(() => tagName.value === 'button');\n // Instead of pre-building attribute fragments as strings (which can\n // accidentally inject invalid attribute names into the template and\n // cause DOMExceptions), compute simple booleans/values and apply\n // attributes explicitly in the template below.\n // Return null when not exact so the attribute is omitted from the DOM\n const ariaCurrentValue = computed<null | string>(() =>\n isExactActive.value ? (props.ariaCurrentValue as string) : null,\n );\n const isDisabled = computed(() => !!props.disabled);\n // External should only apply to anchor tags (links). Make the check explicit.\n // Detect absolute/protocol-relative URLs as external even if the prop\n // wasn't explicitly set by the caller. Only apply to anchor tags.\n const isExternal = computed(() => {\n const toStr = String(props.to || '');\n const looksAbsolute = isAbsoluteUrl(toStr);\n return (looksAbsolute || !!props.external) && tagName.value === 'a';\n });\n\n // Inline style from host `style` attribute.\n const inlineStyle = computed(\n () =>\n (hostStyleRef && hostStyleRef.value) || (props.style as string) || '',\n );\n\n const navigate = (e: MouseEvent) => {\n // Respect pre-handled events, non-left clicks, and modifier keys so\n // default browser behaviors (open-in-new-tab, context menu) work.\n if (\n e.defaultPrevented ||\n e.button !== 0 ||\n e.metaKey ||\n e.altKey ||\n e.ctrlKey ||\n e.shiftKey\n )\n return;\n\n if (isDisabled.value) {\n // Prevent navigation and let assistive tech see disabled state\n e.preventDefault();\n return;\n }\n\n // Block dangerous javascript: URIs explicitly to avoid accidental XSS\n const _targetRaw = String(props.to || '');\n if (isDangerousScheme(_targetRaw)) {\n try {\n e.preventDefault();\n } catch {\n /* swallow */\n }\n devWarn('Blocked unsafe javascript: URI in router-link.to');\n return;\n }\n\n // If this is an external anchor, allow default browser behavior\n if (isExternal.value) return;\n\n e.preventDefault();\n if (props.replace) {\n activeRouterProxy.replace(props.to as string);\n } else {\n activeRouterProxy.push(props.to as string);\n }\n };\n\n return html`\n ${match()\n .when(\n isButton.value,\n html`\n <button\n part=\"button\"\n class=\"${classString.value}\"\n style=\"${inlineStyle.value || null}\"\n aria-current=\"${ariaCurrentValue.value}\"\n disabled=\"${isDisabled.value ? '' : null}\"\n aria-disabled=\"${isDisabled.value ? 'true' : null}\"\n tabindex=\"${isDisabled.value ? '-1' : null}\"\n @click=\"${navigate}\"\n >\n <slot></slot>\n </button>\n `,\n )\n .otherwise(html`\n <a\n part=\"link\"\n href=\"${isDisabled.value ? null : hrefTarget.value}\"\n class=\"${classString.value}\"\n style=\"${inlineStyle.value || null}\"\n aria-current=\"${ariaCurrentValue.value}\"\n aria-disabled=\"${isDisabled.value ? 'true' : null}\"\n tabindex=\"${isDisabled.value ? '-1' : null}\"\n target=\"${isExternal.value ? '_blank' : null}\"\n rel=\"${isExternal.value ? 'noopener noreferrer' : null}\"\n @click=\"${navigate}\"\n ><slot></slot\n ></a>\n `)\n .done()}\n `;\n });\n\n return router;\n}\n\n// Helper functions for SSR-safe active state computation\nexport function computeExactActive(\n currentPath: string,\n targetRaw: string,\n runtimeBase: string,\n): boolean {\n if (isAbsoluteUrl(targetRaw)) return false;\n\n const targetPathOnly = (targetRaw.split('#')[0] || '/').split('?')[0];\n let tgtCandidate = targetPathOnly;\n\n if (runtimeBase && runtimeBase !== '/') {\n const normalizedBase = normalizePathForRoute(runtimeBase);\n const normalizedTarget = normalizePathForRoute(tgtCandidate);\n if (normalizedTarget.startsWith(normalizedBase)) {\n tgtCandidate = normalizedTarget.slice(normalizedBase.length) || '/';\n } else {\n tgtCandidate = normalizedTarget;\n }\n }\n\n const cur = normalizePathForRoute(currentPath);\n const tgt = normalizePathForRoute(tgtCandidate);\n return cur === tgt;\n}\n\nexport function computeActive(\n currentPath: string,\n targetRaw: string,\n runtimeBase: string,\n): boolean {\n if (isAbsoluteUrl(targetRaw)) return false;\n\n const targetPathOnly = (targetRaw.split('#')[0] || '/').split('?')[0];\n let tgtCandidate = targetPathOnly;\n\n if (runtimeBase && runtimeBase !== '/') {\n const normalizedBase = normalizePathForRoute(runtimeBase);\n const normalizedTarget = normalizePathForRoute(tgtCandidate);\n if (normalizedTarget.startsWith(normalizedBase)) {\n tgtCandidate = normalizedTarget.slice(normalizedBase.length) || '/';\n } else {\n tgtCandidate = normalizedTarget;\n }\n }\n\n const cur = normalizePathForRoute(currentPath);\n const tgt = normalizePathForRoute(tgtCandidate);\n\n if (tgt === '/') return cur === '/';\n if (cur === tgt) return true;\n return cur.startsWith(tgt.endsWith('/') ? tgt : tgt + '/');\n}\n"],"names":["DEFAULT_SCROLL_CONFIG","parseQuery","search","serializeQuery","q","isDangerousScheme","s","isAbsoluteUrl","url","safeDecode","value","normalizePathForRoute","p","out","canonicalizeBase","base","normalized","compileCache","escapeSeg","seg","compileRoute","route","raw","routePath","segments","paramNames","regexParts","i","devWarn","name","paramMatch","isSplat","pattern","prefix","e","matchRoute","routes","path","incoming","compiled","regex","m","params","rawValue","findMatchedRoute","r","matchRouteSSR","pathname","MAX_COMPONENT_CACHE_SIZE","componentCache","loadingCache","clearComponentCache","evictLRUComponents","entries","toRemove","b","resolveRouteComponent","cached","isSSR","loadPromise","mod","component","err","errorMsg","devError","activeRouter","setActiveRouter","getActiveRouter","_proxyListeners","_proxyInnerUnsub","_rebindProxy","innerCalledSync","listener","activeRouterProxy","cur","flushDOMUpdates","rebindProxy","partial","currentState","frag","useRouter","config","initialUrl","scrollToFragment","canonicalBase","_scrollConfig","getLocation","initial","store","update","push","replaceFn","back","destroyFn","redirectTracker","MAX_REDIRECT_DEPTH","redirectDepth","runBeforeEnter","to","from","matched","result","redirectKey","runOnEnter","runAfterEnter","matchCache","MATCH_CACHE_SIZE","cachedMatchRoute","entriesToRemove","keys","cleanupScrollState","doScrollToElement","id","offset","element","rect","top","startScrollForNavigation","timeoutMs","resolve","resolved","timeoutId","rafHandle","startTime","safeResolve","attemptScroll","retryScroll","error","isNavigating","navigate","replace","performNavigation","parseNavigationPath","hashIndex","fragment","rawPath","qIndex","pathBeforeQuery","query","stripped","loc","match","beforeEnterResult","onEnterResult","qstr","href","current","fallbackRoute","fallbackMatch","recoveryError","routeList","pathSet","createStore","handlePopState","navigateSSR","initRouter","router","prevRouter","html","ref","unsubRouterView","useOnConnected","useOnDisconnected","comp","resolvedComp","props","useProps","stableCurrentPath","targetPath","ssrActiveStates","computeExactActive","computeActive","unsubRouterLink","useStyle","hostClassRef","hostStyleRef","syncCheckInterval","ctx","latestState","host","hc","hs","isExactActive","computed","runtimeBase","targetRaw","isActive","hrefTarget","pathWithQuery","pathOnly","candidate","normalizedBase","normalizedCandidate","norm","userClasses","list","map","c","classObject","classString","k","tagName","isButton","ariaCurrentValue","isDisabled","isExternal","toStr","inlineStyle","_targetRaw","currentPath","tgtCandidate","normalizedTarget","tgt"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"custom-elements-runtime.router.es.js","sources":["../src/lib/router/path-utils.ts","../src/lib/router/matcher.ts","../src/lib/router/component-loader.ts","../src/lib/router/active-proxy.ts","../src/lib/router/instance.ts"],"sourcesContent":["// ============================================================================\n// CONSTANTS\n// ============================================================================\n\nexport const DEFAULT_SCROLL_CONFIG = {\n enabled: true,\n offset: 0,\n timeoutMs: 2000,\n} as const;\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Parse URL search string into query parameters object.\n * @param search - The search string (with or without leading '?')\n * @returns Object with query parameter key-value pairs\n */\nexport const parseQuery = (search: string): Record<string, string> => {\n if (!search) return {};\n if (typeof URLSearchParams === 'undefined') return {};\n return Object.fromEntries(new URLSearchParams(search));\n};\n\n/**\n * Serialize query parameters object into URL search string.\n * @param q - Query parameters object\n * @returns Search string with leading '?' or empty string\n */\nexport const serializeQuery = (q: Record<string, string> | undefined) => {\n if (!q || Object.keys(q).length === 0) return '';\n try {\n return '?' + new URLSearchParams(q as Record<string, string>).toString();\n } catch {\n return '';\n }\n};\n\n/**\n * Detect dangerous javascript: URIs to prevent XSS attacks.\n * @param s - URL string to check\n * @returns True if the URL uses a dangerous scheme\n */\nexport const isDangerousScheme = (s: string): boolean => {\n if (!s) return false;\n return /^\\s*javascript\\s*:/i.test(s);\n};\n\n/**\n * Check if a URL is absolute (has protocol or is protocol-relative).\n * @param url - URL string to check\n * @returns True if the URL is absolute\n */\nexport const isAbsoluteUrl = (url: string): boolean => {\n return /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(url) || url.startsWith('//');\n};\n\n/**\n * Safely decode a URI component, returning original value on error.\n * @param value - String to decode\n * @returns Decoded string or original value if decoding fails\n */\nexport const safeDecode = (value: string): string => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n};\n\n/**\n * Normalize a path for consistent route matching.\n * Ensures leading slash, removes trailing slash, and collapses duplicate slashes.\n * @param p - Path string to normalize\n * @returns Normalized path string\n */\nexport function normalizePathForRoute(p: string): string {\n if (!p) return '/';\n // Collapse duplicate slashes, ensure leading slash, remove trailing slash\n let out = p.replace(/\\/+/g, '/');\n if (!out.startsWith('/')) out = '/' + out;\n if (out.length > 1 && out.endsWith('/')) out = out.slice(0, -1);\n return out;\n}\n\n/**\n * Canonicalize base path for consistent handling.\n * @param base - Base path string\n * @returns Canonicalized base path (empty string for root)\n */\nexport const canonicalizeBase = (base: string): string => {\n if (!base) return '';\n const normalized = normalizePathForRoute(base);\n return normalized === '/' ? '' : normalized;\n};\n","import type { Route } from './types';\nimport { safeDecode, normalizePathForRoute } from './path-utils';\nimport { devWarn } from '../runtime/logger';\n\n// Cache compiled route regexes to avoid rebuilding on every navigation.\ntype CompiledRoute =\n | { regex: RegExp; paramNames: string[] }\n | { invalid: true };\nconst compileCache: WeakMap<Route, CompiledRoute> = new WeakMap();\n\nfunction escapeSeg(seg: string) {\n return seg.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction compileRoute(route: Route): CompiledRoute {\n const raw = route.path || '/';\n const routePath = normalizePathForRoute(raw);\n\n const segments =\n routePath === '/' ? [] : routePath.split('/').filter(Boolean);\n\n const paramNames: string[] = [];\n const regexParts: string[] = [];\n\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i];\n\n // Anonymous wildcard\n if (seg === '*') {\n // splat must be terminal\n if (i !== segments.length - 1) {\n devWarn(\n `Route '${route.path}' contains a '*' splat in a non-terminal position; splats must be the last segment. This route will be ignored.`,\n );\n return { invalid: true };\n }\n const name = `splat${paramNames.length}`;\n paramNames.push(name);\n // mark splat token; pattern will be built specially so the\n // preceding slash can be optional (allow empty splat)\n regexParts.push('__SPLAT__');\n continue;\n }\n\n const paramMatch = seg.match(/^:([A-Za-z0-9_-]+)(\\*)?$/);\n if (paramMatch) {\n const name = paramMatch[1];\n const isSplat = !!paramMatch[2];\n // If splat, ensure terminal\n if (isSplat && i !== segments.length - 1) {\n devWarn(\n `Route '${route.path}' contains a splat param ':${name}*' in a non-terminal position; splats must be the last segment. This route will be ignored.`,\n );\n return { invalid: true };\n }\n paramNames.push(name);\n regexParts.push(isSplat ? '__SPLAT__' : '([^/]+)');\n continue;\n }\n\n // Static\n regexParts.push(escapeSeg(seg));\n }\n\n let pattern: string;\n if (regexParts.length === 0) {\n pattern = '^/$';\n } else {\n const last = regexParts[regexParts.length - 1];\n if (last === '__SPLAT__') {\n const prefix = regexParts.slice(0, -1).join('/');\n if (!prefix) {\n // route is like '/:rest*' or '/*' -> allow '/' or '/x' etc.\n pattern = '^(?:/(.*))?(?:/)?$';\n } else {\n pattern = `^/${prefix}(?:/(.*))?(?:/)?$`;\n }\n } else {\n pattern = `^/${regexParts.join('/')}(?:/)?$`;\n }\n }\n try {\n const regex = new RegExp(pattern);\n return { regex, paramNames };\n } catch (e) {\n devWarn(`Failed to compile route regex for '${route.path}': ${String(e)}`);\n return { invalid: true };\n }\n}\n\nexport const matchRoute = (\n routes: Route[],\n path: string,\n): { route: Route | null; params: Record<string, string> } => {\n const incoming = normalizePathForRoute(path);\n\n for (const route of routes) {\n let compiled = compileCache.get(route);\n if (!compiled) {\n compiled = compileRoute(route);\n compileCache.set(route, compiled);\n }\n\n if ((compiled as { invalid?: true }).invalid) continue;\n\n const { regex, paramNames } = compiled as {\n regex: RegExp;\n paramNames: string[];\n };\n const m = regex.exec(incoming);\n if (m) {\n const params: Record<string, string> = {};\n\n for (let i = 0; i < paramNames.length; i++) {\n const rawValue = m[i + 1] || '';\n params[paramNames[i]] = rawValue ? safeDecode(rawValue) : '';\n }\n\n return { route, params };\n }\n }\n\n return { route: null, params: {} };\n};\n\n/**\n * Find the first route that matches the given path.\n * Consolidates repeated inline checks like `routes.find(r => matchRoute([r], path).route !== null)`\n */\nexport function findMatchedRoute(routes: Route[], path: string): Route | null {\n for (const r of routes) {\n if (matchRoute([r], path).route !== null) return r;\n }\n return null;\n}\n\n/**\n * Match routes during server-side rendering.\n *\n * Automatically strips any query string and URL fragment from `path` before\n * matching, so callers can safely pass `req.url` (which may include `?key=val`\n * or `#hash`) without causing a missed match.\n *\n * @example\n * ```ts\n * // Both of these correctly match '/blog/:slug'\n * matchRouteSSR(routes, '/blog/hello');\n * matchRouteSSR(routes, '/blog/hello?ref=email#comments');\n * ```\n */\nexport function matchRouteSSR(routes: Route[], path: string) {\n // Strip query string and fragment so callers can pass req.url directly.\n const pathname = path.split('?')[0].split('#')[0];\n return matchRoute(routes, pathname);\n}\n","import type { Route } from './types';\nimport { devError } from '../runtime/logger';\n\n// Async component loader cache with size limit to prevent memory leaks\nconst MAX_COMPONENT_CACHE_SIZE = 50;\nlet componentCache: Record<\n string,\n {\n component: string | HTMLElement | ((...args: unknown[]) => unknown);\n lastAccessed: number;\n }\n> = {};\n\n// Separate cache for loading promises to prevent race conditions\nlet loadingCache: Record<\n string,\n Promise<string | HTMLElement | ((...args: unknown[]) => unknown)>\n> = {};\n\n/**\n * Clear component cache to prevent memory leaks\n */\nexport function clearComponentCache(): void {\n componentCache = {};\n loadingCache = {};\n}\n\n/**\n * Evict least recently used components when cache exceeds size limit\n */\nfunction evictLRUComponents(): void {\n const entries = Object.entries(componentCache);\n if (entries.length <= MAX_COMPONENT_CACHE_SIZE) return;\n\n // Sort by lastAccessed (oldest first) and remove oldest entries\n const sortedEntries = entries.sort(\n ([, a], [, b]) => a.lastAccessed - b.lastAccessed,\n );\n const toRemove = sortedEntries.slice(\n 0,\n entries.length - MAX_COMPONENT_CACHE_SIZE,\n );\n\n for (const [path] of toRemove) {\n delete componentCache[path];\n }\n}\n\n/**\n * Loads a route's component, supporting both static and async.\n * @param route Route object\n * @returns Promise resolving to the component\n */\nexport async function resolveRouteComponent(\n route: Route,\n): Promise<string | HTMLElement | ((...args: unknown[]) => unknown)> {\n if (route.component) return route.component;\n if (route.load) {\n const cached = componentCache[route.path];\n if (cached) {\n // Update last accessed time for LRU tracking\n cached.lastAccessed = Date.now();\n return cached.component;\n }\n\n // Check if already loading to prevent race conditions\n if (loadingCache[route.path] !== undefined) {\n return loadingCache[route.path];\n }\n\n // In SSR context, we need to handle components synchronously when possible\n const isSSR = typeof window === 'undefined';\n\n try {\n // Create loading promise\n const loadPromise = route\n .load()\n .then((mod) => {\n // Evict old components if cache is full\n evictLRUComponents();\n\n const component = mod.default;\n componentCache[route.path] = {\n component,\n lastAccessed: Date.now(),\n };\n\n // Remove from loading cache\n delete loadingCache[route.path];\n\n return component;\n })\n .catch((err) => {\n // Remove from loading cache on error\n delete loadingCache[route.path];\n const errorMsg = err instanceof Error ? err.message : String(err);\n if (isSSR) {\n // In SSR, surface errors more prominently\n devError(\n `SSR component load failed for route: ${route.path}. ${errorMsg}`,\n );\n }\n throw new Error(\n `Failed to load component for route: ${route.path}. ${errorMsg}`,\n );\n });\n\n // Store loading promise to prevent concurrent loads\n loadingCache[route.path] = loadPromise;\n\n return await loadPromise;\n } catch (err) {\n // More descriptive error with original error details\n const errorMsg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Failed to load component for route: ${route.path}. ${errorMsg}`,\n { cause: err },\n );\n }\n }\n throw new Error(`No component or loader defined for route: ${route.path}`);\n}\n","import type { Router, RouteState, Route } from './types';\nimport { devWarn } from '../runtime/logger';\nimport { flushDOMUpdates } from '../runtime/scheduler';\n\n// Module-level reference to the latest initialized router. Tests and\n// components may rely on re-initializing the router during their setup,\n// so exposing this lets components pick up the most recent instance.\nlet activeRouter: Router | null = null;\n\nexport function setActiveRouter(r: Router | null): void {\n activeRouter = r;\n}\n\nexport function getActiveRouter(): Router | null {\n return activeRouter;\n}\n\n// Proxy that provides a stable API for consumers (components/tests).\n// Subscriptions and method calls are forwarded to the currently active\n// router instance. When `activeRouter` changes (via `initRouter`) the\n// proxy rebinds and forwards updates to its listeners so components do\n// not need to re-register on re-init.\ntype RouterListener = (s: RouteState) => void;\nconst _proxyListeners: Set<RouterListener> = new Set();\nlet _proxyInnerUnsub: (() => void) | null = null;\n\nfunction _rebindProxy() {\n // Unsubscribe previous inner subscription to prevent memory leaks\n if (_proxyInnerUnsub) {\n try {\n _proxyInnerUnsub();\n } catch {\n // Ignore unsubscribe errors\n }\n _proxyInnerUnsub = null;\n }\n\n if (activeRouter) {\n // Subscribe to the new router and forward updates\n try {\n // We'll detect whether the inner subscription invokes synchronously.\n // Some store implementations call subscribers immediately; others\n // don't. To guarantee exactly-one initial delivery we record whether\n // the inner callback ran during subscribe and only emit a manual\n // snapshot when it did not.\n let innerCalledSync = false;\n _proxyInnerUnsub = activeRouter.subscribe((s) => {\n innerCalledSync = true;\n // Forward to listeners, using Set iteration which is safe for concurrent modification\n for (const listener of _proxyListeners) {\n try {\n listener(s);\n } catch {\n /* swallow listener errors */\n }\n }\n });\n\n // Update proxy base to reflect active router\n try {\n activeRouterProxy.base = activeRouter.base;\n } catch {\n /* swallow */\n }\n\n // If the inner subscription did not synchronously invoke, emit a\n // single initial snapshot so listeners that were registered while\n // no active router existed receive the current state exactly once.\n if (!innerCalledSync) {\n const cur = activeRouter.getCurrent();\n for (const listener of _proxyListeners) {\n try {\n listener(cur);\n } catch {\n /* swallow */\n }\n }\n } else {\n // Even if inner subscription called synchronously, ensure all listeners\n // receive the current state immediately to handle router re-initialization\n const cur = activeRouter.getCurrent();\n for (const listener of _proxyListeners) {\n try {\n listener(cur);\n } catch {\n /* swallow */\n }\n }\n }\n\n // After synchronously forwarding the current snapshot to proxy\n // listeners, flush any pending DOM updates in browser environments\n // so callers that immediately inspect the DOM observe the updated\n // rendered state.\n try {\n if (typeof window !== 'undefined') flushDOMUpdates();\n } catch {\n /* swallow */\n }\n } catch {\n _proxyInnerUnsub = null;\n }\n }\n}\n\nexport function rebindProxy(): void {\n _rebindProxy();\n}\n\nexport const activeRouterProxy: Router = {\n store: {\n subscribe(listener: RouterListener) {\n if (activeRouter) return activeRouter.store.subscribe(listener);\n // immediate no-op subscribe - provide safe fallback state\n try {\n listener({ path: '/', params: {}, query: {} });\n } catch {\n /* swallow listener errors */\n }\n return () => {};\n },\n getState() {\n return activeRouter\n ? activeRouter.getCurrent()\n : { path: '/', params: {}, query: {} };\n },\n setState(\n partial:\n | Partial<RouteState>\n | ((prev: RouteState) => Partial<RouteState>),\n ) {\n if (!activeRouter) return;\n try {\n if (typeof partial === 'function') {\n activeRouter.store.setState(\n partial as (prev: RouteState) => Partial<RouteState>,\n );\n } else {\n activeRouter.store.setState(partial as Partial<RouteState>);\n }\n } catch {\n /* swallow */\n }\n },\n },\n subscribe(listener: RouterListener) {\n // Defensive check - ensure listener is a function\n if (typeof listener !== 'function') {\n devWarn('activeRouterProxy.subscribe: listener must be a function');\n return () => {};\n }\n\n // Add the listener to the proxy set\n _proxyListeners.add(listener);\n\n // Ensure we are bound to the active router. If not bound, rebind so\n // the inner subscription will forward updates to `_proxyListeners`.\n if (activeRouter) {\n if (!_proxyInnerUnsub) {\n // Rebind will synchronously forward the current state to all\n // proxy listeners (including the one we just pushed). Don't\n // call the listener again here to avoid double-invocation.\n _rebindProxy();\n } else {\n // Inner subscription already present; deliver a synchronous\n // snapshot only to the newly added listener.\n try {\n const currentState = activeRouter.getCurrent();\n if (currentState) {\n listener(currentState);\n }\n } catch (err) {\n devWarn('activeRouterProxy subscription failed', err);\n }\n }\n } else {\n // No active router yet - provide fallback state\n try {\n listener({ path: '/', params: {}, query: {} });\n } catch (err) {\n devWarn('activeRouterProxy fallback state delivery failed', err);\n }\n }\n\n // Return unsubscribe with additional safety checks\n return () => {\n try {\n _proxyListeners.delete(listener);\n // If no more proxy listeners remain, unsubscribe inner subscription\n // to avoid retaining unused references. It will be rebound on demand.\n if (_proxyListeners.size === 0 && _proxyInnerUnsub) {\n try {\n _proxyInnerUnsub();\n } catch (err) {\n devWarn('activeRouterProxy inner unsubscribe failed', err);\n }\n _proxyInnerUnsub = null;\n }\n } catch (err) {\n devWarn('activeRouterProxy unsubscribe failed', err);\n }\n };\n },\n getCurrent() {\n return activeRouter\n ? activeRouter.getCurrent()\n : { path: '/', params: {}, query: {} };\n },\n async push(path: string) {\n if (!activeRouter) return Promise.resolve();\n return activeRouter.push(path);\n },\n async replace(path: string) {\n if (!activeRouter) return Promise.resolve();\n return activeRouter.replace(path);\n },\n back() {\n if (!activeRouter) return;\n return activeRouter.back();\n },\n matchRoute(path: string) {\n return activeRouter\n ? activeRouter.matchRoute(path)\n : { route: null as Route | null, params: {} };\n },\n resolveRouteComponent(route: Route) {\n return activeRouter\n ? activeRouter.resolveRouteComponent(route)\n : Promise.reject(new Error('No active router'));\n },\n base: '',\n scrollToFragment(frag?: string) {\n return activeRouter\n ? activeRouter.scrollToFragment(frag)\n : Promise.resolve(false);\n },\n destroy() {\n if (activeRouter) activeRouter.destroy();\n },\n};\n","import { html } from '../runtime/template-compiler';\nimport { component } from '../runtime/component';\nimport {\n useProps,\n useOnConnected,\n useOnDisconnected,\n useStyle,\n getCurrentComponentContext,\n} from '../runtime/hooks';\nimport { ref, computed } from '../runtime/reactive';\nimport { flushDOMUpdates } from '../runtime/scheduler';\nimport { createStore } from '../store';\nimport { devError, devWarn } from '../runtime/logger';\nimport { match } from '../directives';\nimport type {\n RouteState,\n Route,\n RouterLinkProps,\n RouterConfig,\n Router,\n} from './types';\nimport {\n DEFAULT_SCROLL_CONFIG,\n isDangerousScheme,\n isAbsoluteUrl,\n canonicalizeBase,\n normalizePathForRoute,\n parseQuery,\n serializeQuery,\n} from './path-utils';\nimport { matchRoute, findMatchedRoute } from './matcher';\nimport { clearComponentCache, resolveRouteComponent } from './component-loader';\nimport {\n activeRouterProxy,\n setActiveRouter,\n getActiveRouter,\n rebindProxy,\n} from './active-proxy';\n\nexport function useRouter(config: RouterConfig): Router {\n const { routes, base = '', initialUrl, scrollToFragment = true } = config;\n\n // Canonicalize base so callers and internal logic have a single\n // representation. Normalized base will be '' for root or '/x' (no\n // trailing slash). This prevents accidental double-prefixing like\n // '/app/app/about' and makes startsWith checks reliable.\n const canonicalBase = canonicalizeBase(base);\n\n // Normalize scroll configuration\n const _scrollConfig =\n typeof scrollToFragment === 'boolean'\n ? { ...DEFAULT_SCROLL_CONFIG, enabled: scrollToFragment }\n : { ...DEFAULT_SCROLL_CONFIG, ...scrollToFragment };\n\n // getLocation/initial include an optional `fragment` field in practice.\n let getLocation: () => {\n path: string;\n query: Record<string, string>;\n fragment?: string;\n };\n let initial: {\n path: string;\n query: Record<string, string>;\n fragment?: string;\n };\n let store: ReturnType<typeof createStore<RouteState>>;\n let update: (replace?: boolean) => Promise<void>;\n let push: (path: string) => Promise<void>;\n let replaceFn: (path: string) => Promise<void>;\n let back: () => void;\n let destroyFn: () => void = () => {};\n\n // Track redirects to prevent infinite loops\n const redirectTracker = new Set<string>();\n const MAX_REDIRECT_DEPTH = 10;\n let redirectDepth = 0;\n\n // Run matching route guards/hooks\n const runBeforeEnter = async (\n to: RouteState,\n from: RouteState,\n ): Promise<boolean | string> => {\n const matched = findMatchedRoute(routes, to.path);\n if (!matched || !matched.beforeEnter) return true;\n try {\n const result = await matched.beforeEnter(to, from);\n if (typeof result === 'string') {\n // Check for redirect loops\n const redirectKey = `${to.path}->${result}`;\n if (\n redirectTracker.has(redirectKey) ||\n redirectDepth >= MAX_REDIRECT_DEPTH\n ) {\n devError(`Redirect loop detected: ${redirectKey}`);\n return false;\n }\n return result; // Return redirect path instead of navigating immediately\n }\n return result !== false;\n } catch (err) {\n devError('beforeEnter error', err);\n // Reset store to previous state on guard error to maintain consistency\n try {\n store.setState(from);\n } catch {\n /* swallow setState errors */\n }\n // Always let guard errors bubble up for proper error handling\n throw err;\n }\n };\n\n const runOnEnter = async (\n to: RouteState,\n from: RouteState,\n ): Promise<boolean | string> => {\n const matched = findMatchedRoute(routes, to.path);\n if (!matched || !matched.onEnter) return true;\n try {\n const result = await matched.onEnter(to, from);\n if (typeof result === 'string') {\n // Check for redirect loops\n const redirectKey = `${to.path}->${result}`;\n if (\n redirectTracker.has(redirectKey) ||\n redirectDepth >= MAX_REDIRECT_DEPTH\n ) {\n devError(`Redirect loop detected: ${redirectKey}`);\n return false;\n }\n return result; // Return redirect path instead of navigating immediately\n }\n return result !== false;\n } catch (err) {\n devError('onEnter error', err);\n // Reset store to previous state on guard error to maintain consistency\n try {\n store.setState(from);\n } catch {\n /* swallow setState errors */\n }\n // Always let guard errors bubble up for proper error handling\n throw err;\n }\n };\n\n const runAfterEnter = (to: RouteState, from: RouteState): void => {\n const matched = findMatchedRoute(routes, to.path);\n if (!matched || !matched.afterEnter) return;\n try {\n const result: void | Promise<void> = matched.afterEnter(to, from);\n if (result instanceof Promise) {\n result.catch((err: unknown) => {\n devError('afterEnter async error', err);\n });\n }\n } catch (err) {\n devError('afterEnter error', err);\n }\n };\n\n // Cache for route matching to avoid repeated expensive operations\n const matchCache = new Map<\n string,\n { route: Route | null; params: Record<string, string> }\n >();\n const MATCH_CACHE_SIZE = 100;\n\n const cachedMatchRoute = (path: string) => {\n if (matchCache.has(path)) {\n return matchCache.get(path)!;\n }\n\n const result = matchRoute(routes, path);\n\n // Implement proper LRU by clearing oldest entries when cache is full\n if (matchCache.size >= MATCH_CACHE_SIZE) {\n // Remove oldest 25% of entries to avoid frequent cleanup\n const entriesToRemove = Math.floor(MATCH_CACHE_SIZE * 0.25);\n const keys = Array.from(matchCache.keys());\n for (let i = 0; i < entriesToRemove && i < keys.length; i++) {\n matchCache.delete(keys[i]);\n }\n }\n\n matchCache.set(path, result);\n return result;\n };\n\n // Scroll management with per-promise tracking\n const cleanupScrollState = () => {\n // No global cleanup needed - each promise manages its own lifecycle\n };\n\n async function doScrollToElement(id: string, offset = 0): Promise<boolean> {\n try {\n const element = document.getElementById(id);\n if (!element) {\n return false;\n }\n\n if (offset > 0) {\n try {\n const rect = element.getBoundingClientRect();\n const top = Math.max(0, window.scrollY + rect.top - offset);\n if (typeof window.scrollTo === 'function') {\n window.scrollTo({ top, behavior: 'auto' });\n }\n } catch {\n try {\n element.scrollIntoView();\n } catch {\n return false;\n }\n }\n } else {\n if (typeof element.scrollIntoView === 'function') {\n try {\n element.scrollIntoView({\n behavior: 'auto',\n block: 'start',\n inline: 'nearest',\n });\n } catch {\n try {\n element.scrollIntoView();\n } catch {\n return false;\n }\n }\n }\n }\n return true;\n } catch {\n return false;\n }\n }\n\n // Scroll with per-promise lifecycle management and retry for missing elements\n function startScrollForNavigation(\n id: string,\n offset: number = 0,\n timeoutMs: number = 2000,\n ): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n let resolved = false;\n let timeoutId: number | null = null;\n let rafHandle: number | null = null;\n const startTime = Date.now();\n\n const safeResolve = (value: boolean) => {\n if (resolved) return;\n resolved = true;\n if (timeoutId) clearTimeout(timeoutId);\n // Cancel any pending rAF so orphaned retry loops don't keep firing\n // after the promise has already resolved (e.g. on rapid navigation).\n if (rafHandle !== null) cancelAnimationFrame(rafHandle);\n resolve(value);\n };\n\n const attemptScroll = async () => {\n if (resolved) return;\n\n try {\n // Try immediate scroll first\n if (await doScrollToElement(id, offset)) {\n return safeResolve(true);\n }\n\n // For missing elements, continue retrying until timeout\n const retryScroll = async () => {\n if (resolved) return;\n\n const elapsed = Date.now() - startTime;\n if (elapsed >= timeoutMs) {\n return safeResolve(false);\n }\n\n try {\n if (await doScrollToElement(id, offset)) {\n return safeResolve(true);\n }\n\n rafHandle = requestAnimationFrame(retryScroll);\n } catch (error) {\n devWarn('Scroll retry attempt failed:', error);\n rafHandle = requestAnimationFrame(retryScroll);\n }\n };\n\n // Start retry loop after initial attempt\n rafHandle = requestAnimationFrame(retryScroll);\n } catch (error) {\n devWarn('Initial scroll attempt failed:', error);\n safeResolve(false);\n }\n };\n\n // Set timeout as final safety net\n timeoutId = setTimeout(() => {\n safeResolve(false);\n }, timeoutMs);\n\n // Start the attempt immediately with error handling\n attemptScroll().catch((error) => {\n devWarn('Scroll attempt failed:', error);\n safeResolve(false);\n });\n });\n }\n\n // Navigation lock to prevent concurrent navigation race conditions\n let isNavigating = false;\n\n const navigate = async (path: string, replace = false): Promise<void> => {\n // Prevent concurrent navigation\n if (isNavigating) {\n devWarn(`Navigation to ${path} blocked - navigation already in progress`);\n return;\n }\n\n isNavigating = true;\n redirectDepth = 0;\n redirectTracker.clear();\n\n try {\n await performNavigation(path, replace);\n } finally {\n isNavigating = false;\n redirectDepth = 0;\n redirectTracker.clear();\n }\n };\n\n // Extract path parsing logic for reuse in SSR\n const parseNavigationPath = (path: string) => {\n const hashIndex = path.indexOf('#');\n const fragment = hashIndex >= 0 ? path.slice(hashIndex + 1) : '';\n const rawPath = hashIndex >= 0 ? path.slice(0, hashIndex) : path;\n const qIndex = rawPath.indexOf('?');\n const pathBeforeQuery = qIndex >= 0 ? rawPath.slice(0, qIndex) : rawPath;\n const query = qIndex >= 0 ? parseQuery(rawPath.slice(qIndex)) : {};\n const stripped = pathBeforeQuery.startsWith(canonicalBase)\n ? pathBeforeQuery.slice(canonicalBase.length)\n : pathBeforeQuery;\n const normalized = normalizePathForRoute(stripped || '/');\n return {\n path: normalized,\n query,\n fragment,\n };\n };\n\n const performNavigation = async (\n path: string,\n replace = false,\n ): Promise<void> => {\n try {\n const loc = parseNavigationPath(path);\n const match = cachedMatchRoute(loc.path);\n if (!match.route) throw new Error(`No route found for ${loc.path}`);\n\n const from = store.getState();\n const to: RouteState = {\n path: loc.path,\n params: match.params,\n query: loc.query,\n fragment: (loc as { fragment?: string }).fragment,\n };\n\n // beforeEnter guard\n const beforeEnterResult = await runBeforeEnter(to, from);\n if (beforeEnterResult === false) return;\n if (typeof beforeEnterResult === 'string') {\n // Handle redirect\n redirectDepth++;\n const redirectKey = `${to.path}->${beforeEnterResult}`;\n redirectTracker.add(redirectKey);\n await performNavigation(beforeEnterResult, true);\n return;\n }\n\n // onEnter guard (right before commit)\n const onEnterResult = await runOnEnter(to, from);\n if (onEnterResult === false) return;\n if (typeof onEnterResult === 'string') {\n // Handle redirect\n redirectDepth++;\n const redirectKey = `${to.path}->${onEnterResult}`;\n redirectTracker.add(redirectKey);\n await performNavigation(onEnterResult, true);\n return;\n }\n\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n const qstr = serializeQuery(loc.query);\n const href =\n canonicalBase +\n loc.path +\n (qstr || '') +\n (loc.fragment ? '#' + loc.fragment : '');\n if (replace) {\n window.history.replaceState({}, '', href);\n } else {\n window.history.pushState({}, '', href);\n }\n }\n\n store.setState(to);\n\n // afterEnter hook (post commit)\n runAfterEnter(to, from);\n\n // If there's a fragment (hash) preserve it on the URL and attempt to\n // scroll to the element with that id on client-side navigation.\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n try {\n const frag = (to as { fragment?: string }).fragment;\n if (_scrollConfig.enabled && frag) {\n // Start the robust scroll flow (observer + timeout + cancellation)\n startScrollForNavigation(\n String(frag),\n _scrollConfig.offset,\n _scrollConfig.timeoutMs,\n ).catch(() => {});\n }\n } catch {\n /* swallow */\n }\n }\n } catch (err) {\n devError('Navigation error:', err);\n\n // If this is a guard error, re-throw it so the promise rejects properly\n if (\n err instanceof Error &&\n (err.stack?.includes('runBeforeEnter') ||\n err.stack?.includes('runOnEnter'))\n ) {\n throw err;\n }\n\n // For other navigation errors, ensure store state remains consistent\n try {\n const current = store.getState();\n const targetMatches = matchRoute(routes, current.path);\n if (!targetMatches.route) {\n // If current state is invalid, reset to a valid route or root\n let fallbackRoute = routes.find((r) => r.path === '/');\n if (!fallbackRoute) {\n // Find any route that doesn't have dynamic segments as fallback\n fallbackRoute = routes.find(\n (r) => !r.path.includes(':') && !r.path.includes('*'),\n );\n }\n if (!fallbackRoute && routes.length > 0) {\n fallbackRoute = routes[0];\n }\n\n if (fallbackRoute) {\n const fallbackMatch = matchRoute(routes, fallbackRoute.path);\n store.setState({\n path: fallbackRoute.path,\n params: fallbackMatch.params,\n query: {},\n });\n } else {\n devError('No fallback route available for error recovery');\n }\n }\n } catch (recoveryError) {\n devWarn(\n 'State recovery failed during navigation error:',\n recoveryError,\n );\n }\n }\n };\n\n // Validate routes configuration\n const validateRoutes = (routeList: Route[]): boolean => {\n if (!routeList || routeList.length === 0) {\n devError('Router configuration error: No routes provided');\n return false;\n }\n\n const pathSet = new Set<string>();\n for (const route of routeList) {\n if (!route.path) {\n devError('Router configuration error: Route missing path', route);\n return false;\n }\n\n if (pathSet.has(route.path)) {\n devWarn(`Duplicate route path detected: ${route.path}`);\n }\n pathSet.add(route.path);\n\n if (!route.component && !route.load) {\n devWarn(`Route '${route.path}' has no component or load function`);\n }\n }\n return true;\n };\n\n // Validate configuration before proceeding (non-fatal for compatibility)\n validateRoutes(routes);\n\n // Pre-compile all routes for better SSR performance\n const isSSRMode =\n typeof window === 'undefined' || typeof initialUrl !== 'undefined';\n if (isSSRMode) {\n for (const route of routes) {\n // Force compilation of all routes during SSR initialization\n cachedMatchRoute(route.path);\n }\n devWarn(`Pre-compiled ${routes.length} routes for SSR`);\n }\n\n // If an explicit `initialUrl` is provided we treat this as SSR/static rendering\n // even if a `window` exists (useful for hydration tests). Browser mode only\n // applies when `initialUrl` is undefined.\n if (\n typeof window !== 'undefined' &&\n typeof document !== 'undefined' &&\n typeof initialUrl === 'undefined'\n ) {\n // Browser mode\n getLocation = () => {\n try {\n const url = new URL(window.location.href);\n const raw = url.pathname;\n const stripped = raw.startsWith(canonicalBase)\n ? raw.slice(canonicalBase.length)\n : raw;\n const path = normalizePathForRoute(stripped || '/');\n const query = parseQuery(url.search);\n const fragment = url.hash && url.hash.length ? url.hash.slice(1) : '';\n return { path, query, fragment };\n } catch (error) {\n devWarn('Invalid URL detected, falling back to safe defaults', error);\n return { path: '/', query: {}, fragment: '' };\n }\n };\n\n initial = getLocation();\n const match = cachedMatchRoute(initial.path);\n store = createStore<RouteState>({\n path: initial.path,\n params: match.params,\n query: initial.query,\n fragment: (initial as { fragment?: string }).fragment,\n });\n\n update = async (replace = false) => {\n const loc = getLocation();\n await navigate(loc.path, replace);\n };\n\n const handlePopState = () => update(true);\n window.addEventListener('popstate', handlePopState);\n destroyFn = () => window.removeEventListener('popstate', handlePopState);\n\n push = (path: string) => navigate(path, false);\n replaceFn = (path: string) => navigate(path, true);\n back = () => window.history.back();\n\n // Run initial navigation through the guard pipeline so beforeEnter guards\n // fire on the entry URL (e.g. protected routes redirect on hard refresh).\n // queueMicrotask defers until after setActiveRouter()/rebindProxy() complete,\n // ensuring subscribers are bound before the navigation state updates.\n queueMicrotask(() => {\n navigate(initial.path, true).catch((err) => {\n devError('Initial navigation error:', err);\n });\n });\n } else {\n // SSR mode\n getLocation = () => {\n try {\n const url = new URL(initialUrl || '/', 'http://localhost');\n const raw = url.pathname;\n const stripped = raw.startsWith(canonicalBase)\n ? raw.slice(canonicalBase.length)\n : raw;\n const path = normalizePathForRoute(stripped || '/');\n const query = parseQuery(url.search);\n const fragment = url.hash && url.hash.length ? url.hash.slice(1) : '';\n return { path, query, fragment };\n } catch (error) {\n devWarn(\n 'Invalid SSR URL detected, falling back to safe defaults',\n error,\n );\n return { path: '/', query: {}, fragment: '' };\n }\n };\n\n initial = getLocation();\n const match = cachedMatchRoute(initial.path);\n store = createStore<RouteState>({\n path: initial.path,\n params: match.params,\n query: initial.query,\n fragment: (initial as { fragment?: string }).fragment,\n });\n\n update = async () => {\n const loc = getLocation();\n await navigateSSR(loc.path);\n };\n\n // SSR navigation contract:\n // - `push` / `replace` call into `navigateSSR` and return a Promise.\n // - On the server we intentionally surface navigation failures so\n // server-side logic (or tests) can react: missing routes or thrown\n // errors from `beforeEnter`/`onEnter` will cause the Promise to\n // reject. This lets the server render 404s or abort builds.\n // - For valid routes the server-side navigation resolves and updates\n // the internal store state so rendered output matches the target\n // path. The `back()` operation is client-only and is a synchronous\n // no-op in SSR mode.\n const navigateSSR = async (path: string) => {\n // Prevent infinite recursion in SSR mode\n redirectDepth++;\n if (redirectDepth > MAX_REDIRECT_DEPTH) {\n devError(`SSR redirect depth exceeded for path: ${path}`);\n return;\n }\n\n try {\n const loc = parseNavigationPath(path);\n const match = cachedMatchRoute(loc.path);\n // In SSR mode we intentionally surface navigation errors (missing\n // route) to the caller so server-side logic may handle them. If no\n // route matches, throw and let the caller observe the rejection.\n if (!match.route) throw new Error(`No route found for ${loc.path}`);\n\n const from = store.getState();\n const to: RouteState = {\n path: loc.path,\n params: match.params,\n query: loc.query,\n fragment: (loc as { fragment?: string }).fragment,\n };\n\n // beforeEnter guard with redirect tracking - let errors bubble up in SSR\n const matched = findMatchedRoute(routes, to.path);\n if (matched?.beforeEnter) {\n const result = await matched.beforeEnter(to, from);\n if (typeof result === 'string') {\n // Handle redirect with tracking\n const redirectKey = `${to.path}->${result}`;\n redirectTracker.add(redirectKey);\n await navigateSSR(result);\n return;\n }\n if (result === false) return;\n }\n\n // onEnter guard with redirect tracking - let errors bubble up in SSR\n if (matched?.onEnter) {\n const result = await matched.onEnter(to, from);\n if (typeof result === 'string') {\n // Handle redirect with tracking\n const redirectKey = `${to.path}->${result}`;\n redirectTracker.add(redirectKey);\n await navigateSSR(result);\n return;\n }\n if (result === false) return;\n }\n\n store.setState(to);\n\n // afterEnter hook\n if (matched?.afterEnter) {\n matched.afterEnter(to, from);\n }\n } catch (err) {\n // Surface SSR navigation errors so callers (and tests) can observe\n // failures during server-side resolution.\n devError('SSR navigation error:', err);\n throw err;\n }\n };\n\n push = async (path: string) => {\n redirectDepth = 0;\n redirectTracker.clear();\n return navigateSSR(path);\n };\n replaceFn = async (path: string) => {\n redirectDepth = 0;\n redirectTracker.clear();\n return navigateSSR(path);\n };\n back = () => {};\n }\n\n const router: Router = {\n _cleanupScrollState: cleanupScrollState,\n destroy: destroyFn,\n store,\n push,\n replace: replaceFn,\n back,\n subscribe: store.subscribe,\n matchRoute: (path: string) => cachedMatchRoute(path),\n getCurrent: (): RouteState => store.getState(),\n resolveRouteComponent,\n base: canonicalBase,\n // Public API: allow components or tests to explicitly request scrolling to\n // a fragment when they know their DOM is ready. Returns true if scrolled.\n scrollToFragment: (frag?: string) => {\n const id = frag || (store.getState() as RouteState).fragment;\n if (!id) return Promise.resolve(false);\n if (typeof window === 'undefined' || typeof document === 'undefined')\n return Promise.resolve(false);\n return startScrollForNavigation(\n id,\n _scrollConfig.offset,\n _scrollConfig.timeoutMs,\n );\n },\n };\n\n return router;\n}\n\n/**\n * Singleton router instance for global access.\n *\n * Define here to prevent circular dependency\n * issue with component.\n */\n\nexport function initRouter(config: RouterConfig): Router {\n // Clear component cache on reinitialization to prevent stale components\n clearComponentCache();\n\n const router = useRouter(config);\n\n // Clean up previous router instance to prevent listener accumulation\n const prevRouter = getActiveRouter();\n if (prevRouter) {\n try {\n prevRouter.destroy();\n } catch {\n // Ignore cleanup errors - function may not exist in older instances\n }\n try {\n prevRouter._cleanupScrollState?.();\n } catch {\n // Ignore cleanup errors - function may not exist in older instances\n }\n }\n // Expose the most recently initialized router to components defined\n // earlier in the process (tests may call initRouter multiple times).\n // Components reference `activeRouterProxy` so re-calling initRouter updates\n // the router instance they use.\n setActiveRouter(router);\n // Rebind the proxy so any existing subscribers are forwarded to the\n // newly initialized router immediately.\n try {\n rebindProxy();\n try {\n // Only attempt to flush DOM updates in browser environments.\n if (typeof window !== 'undefined') flushDOMUpdates();\n } catch {\n // Ignore DOM flush errors\n }\n\n // Additional flush after rebind to ensure all router-link components\n // have updated their active states before any synchronous inspection\n try {\n if (typeof window !== 'undefined') {\n // Use a microtask to allow reactive computations to complete\n queueMicrotask(() => {\n try {\n flushDOMUpdates();\n } catch {\n /* swallow */\n }\n });\n }\n } catch {\n /* swallow */\n }\n } catch {\n // Ignore proxy rebind errors\n }\n\n component('router-view', async () => {\n // In SSR, prefer the per-request router threaded through the component\n // context over the module-level activeRouterProxy singleton. This enables\n // concurrent SSR renders — each request carries its own router instance\n // with its own URL state, so renders never cross-contaminate.\n // In the browser there is no _router on the context; fall back to the\n // global proxy as before.\n const ctx = getCurrentComponentContext();\n const ctxRouter = ctx?._router as Router | undefined;\n const routerToUse = ctxRouter ?? activeRouterProxy;\n\n if (!getActiveRouter() && !ctxRouter) return html`<div>Router not initialized.</div>`;\n\n const current = ref(routerToUse.getCurrent());\n const isSSR = typeof window === 'undefined';\n\n // We'll capture the unsubscribe function when the component connects\n // and register a disconnect cleanup during render-time (useOnDisconnected\n // must be called during the component render/execution).\n let unsubRouterView: (() => void) | undefined;\n\n // Only set up subscriptions in browser environment\n if (!isSSR) {\n useOnConnected(() => {\n try {\n if (typeof routerToUse.subscribe === 'function') {\n unsubRouterView = routerToUse.subscribe((s) => {\n try {\n // Validate state before updating to prevent corruption\n if (s && typeof s === 'object' && typeof s.path === 'string') {\n current.value = s;\n } else {\n devWarn('router-view received invalid state', s);\n // Fallback to safe default state\n current.value = { path: '/', params: {}, query: {} };\n }\n } catch (e) {\n devWarn('router-view subscription update failed', e);\n // Attempt to recover with safe state\n try {\n current.value = { path: '/', params: {}, query: {} };\n } catch {\n /* swallow recovery errors */\n }\n }\n });\n }\n } catch (e) {\n devWarn('router-view subscribe failed', e);\n }\n });\n\n useOnDisconnected(() => {\n if (typeof unsubRouterView === 'function') {\n try {\n unsubRouterView();\n } catch (e) {\n devWarn('router-view unsubscribe failed', e);\n }\n unsubRouterView = undefined; // Clear reference to prevent memory leaks\n }\n });\n }\n\n const match = routerToUse.matchRoute(current.value.path);\n if (!match || !match.route) return html`<div>Not found</div>`;\n\n // Resolve the component (supports cached async loaders)\n try {\n const compRaw = await routerToUse.resolveRouteComponent(\n match.route!,\n );\n const comp = compRaw as\n | string\n | HTMLElement\n | ((...args: unknown[]) => unknown)\n | undefined;\n // String tag (custom element) -> render as VNode, forwarding route params as attrs\n // vnode.props is structured as { props, attrs, directives }; params go in attrs\n // so the renderer passes them to the element via setAttributeSmart.\n if (typeof comp === 'string') {\n return { tag: comp, props: { attrs: { ...current.value.params } }, children: [] };\n }\n\n // Function component (sync or async) -> call and return its VNode(s)\n if (typeof comp === 'function') {\n const out = comp();\n const resolved = out instanceof Promise ? out : Promise.resolve(out);\n return resolved.then((resolvedComp) => {\n if (typeof resolvedComp === 'string')\n return { tag: resolvedComp, props: {}, children: [] };\n return resolvedComp;\n });\n }\n\n return html`<div>Invalid route component</div>`;\n } catch {\n return html`<div>Invalid route component</div>`;\n }\n });\n\n component('router-link', () => {\n // Declare props via useProps so observedAttributes are correct\n const props = useProps<Partial<RouterLinkProps>>({\n to: '',\n tag: 'a',\n replace: false,\n exact: false,\n activeClass: 'active',\n exactActiveClass: 'exact-active',\n ariaCurrentValue: 'page',\n disabled: false,\n external: false,\n // allow host `class` and `style` attributes to be read via useProps\n class: '',\n style: '',\n });\n\n const isSSR = typeof window === 'undefined';\n const current = ref(activeRouterProxy.getCurrent());\n\n // For SSR, compute stable active states to prevent hydration mismatches\n const stableCurrentPath = current.value?.path || '/';\n const targetPath = String(props.to || '');\n\n // Pre-compute SSR-safe active states\n const ssrActiveStates = isSSR\n ? {\n isExactActive: computeExactActive(\n stableCurrentPath,\n targetPath,\n activeRouterProxy.base,\n ),\n isActive: computeActive(\n stableCurrentPath,\n targetPath,\n activeRouterProxy.base,\n ),\n isExternal: isAbsoluteUrl(targetPath) || !!props.external,\n }\n : null;\n\n let unsubRouterLink: (() => void) | undefined;\n\n // Keep a minimal internal host-scoped style for element display.\n // Host `style` will be applied to the inner anchor/button element.\n useStyle(() => `a,button{display:inline-block;}`);\n\n // We capture host attributes at connection time and migrate them to\n // internal refs so we can remove them from the host. This prevents\n // global/author CSS targeting the host from styling the host element\n // itself while still allowing authors to use `class`/`style` on the\n // router-link to style the inner anchor/button.\n const hostClassRef = ref((props.class as string) || '');\n const hostStyleRef = ref((props.style as string) || '');\n\n // Only set up DOM interactions in browser environment\n if (!isSSR) {\n let syncCheckInterval: ReturnType<typeof setInterval> | null = null;\n\n useOnConnected((ctx?: unknown) => {\n try {\n if (typeof activeRouterProxy.subscribe === 'function') {\n unsubRouterLink = activeRouterProxy.subscribe((s) => {\n try {\n // Validate state before updating to prevent corruption\n if (s && typeof s === 'object' && typeof s.path === 'string') {\n current.value = s;\n } else {\n devWarn('router-link received invalid state', s);\n // Fallback to safe default state\n current.value = { path: '/', params: {}, query: {} };\n }\n } catch (e) {\n devWarn('router-link subscription update failed', e);\n // Attempt to recover with safe state\n try {\n current.value = { path: '/', params: {}, query: {} };\n } catch {\n /* swallow recovery errors */\n }\n }\n });\n\n // Immediately sync current state after subscription to ensure\n // correct active state even if router was initialized after component creation\n try {\n const currentState = activeRouterProxy.getCurrent();\n if (currentState && typeof currentState.path === 'string') {\n current.value = currentState;\n }\n } catch (e) {\n devWarn('router-link initial state sync failed', e);\n }\n\n // Set up periodic sync check to ensure state accuracy after router changes\n // This catches edge cases where subscription updates might be missed\n syncCheckInterval = setInterval(() => {\n try {\n const latestState = activeRouterProxy.getCurrent();\n if (latestState && typeof latestState.path === 'string') {\n // Only update if state actually changed to avoid unnecessary re-renders\n if (\n JSON.stringify(current.value) !==\n JSON.stringify(latestState)\n ) {\n current.value = latestState;\n }\n }\n } catch {\n // Silent failure - don't spam console with periodic check errors\n }\n }, 100); // Check every 100ms\n }\n } catch (e) {\n devWarn('router-link subscribe failed', e);\n }\n\n // Migrate host `class`/`style` into internal refs and remove them\n // from the host so only the inner element is styled.\n try {\n const host = (ctx as { _host?: HTMLElement } | undefined)?._host;\n if (typeof HTMLElement !== 'undefined' && host instanceof HTMLElement) {\n const hc = host.getAttribute('class');\n const hs = host.getAttribute('style');\n if (hc) hostClassRef.value = hc;\n if (hs) hostStyleRef.value = hs;\n // Remove attributes from host to avoid styling the host\n if (hc !== null) host.removeAttribute('class');\n if (hs !== null) host.removeAttribute('style');\n // Re-render to ensure migrated host classes/styles are applied\n // to the internal anchor/button element.\n try {\n // The `ctx` passed into useOnConnected is the component context\n // which exposes `_requestRender`. Call that to re-render after\n // migrating host attributes into internal refs.\n (\n ctx as unknown as { _requestRender?: () => void }\n )?._requestRender?.();\n // Ensure DOM updates from the scheduled render are flushed so\n // callers (and tests) can synchronously observe migrated\n // classes/styles on the inner anchor/button.\n try {\n flushDOMUpdates();\n } catch {\n /* ignore */\n }\n } catch {\n /* ignore */\n }\n }\n } catch (e) {\n devWarn('router-link host migration failed', e);\n }\n });\n\n useOnDisconnected(() => {\n // Clean up router subscription\n if (typeof unsubRouterLink === 'function') {\n try {\n unsubRouterLink();\n } catch (e) {\n devWarn('router-link unsubscribe failed', e);\n } finally {\n unsubRouterLink = undefined; // Clear reference to prevent memory leaks\n }\n }\n\n // Clean up sync check interval\n if (syncCheckInterval) {\n try {\n clearInterval(syncCheckInterval);\n } catch (e) {\n devWarn('router-link sync interval cleanup failed', e);\n } finally {\n syncCheckInterval = null;\n }\n }\n });\n }\n\n // Use pre-computed values for SSR or dynamic computed for client\n const isExactActive = computed(() => {\n if (isSSR && ssrActiveStates) {\n return ssrActiveStates.isExactActive;\n }\n\n try {\n const runtimeBase = activeRouterProxy.base ?? '';\n const targetRaw = (props.to as string) || '';\n\n // Defensive check for current value\n if (!current.value || typeof current.value.path !== 'string') {\n return false;\n }\n\n return computeExactActive(current.value.path, targetRaw, runtimeBase);\n } catch (err) {\n devWarn('isExactActive computation error', err);\n return false;\n }\n });\n\n const isActive = computed(() => {\n if (isSSR && ssrActiveStates) {\n return ssrActiveStates.isActive;\n }\n\n try {\n const runtimeBase = activeRouterProxy.base ?? '';\n const targetRaw = (props.to as string) || '';\n\n // Defensive check for current value\n if (!current.value || typeof current.value.path !== 'string') {\n return false;\n }\n\n if (props.exact) return isExactActive.value;\n return computeActive(current.value.path, targetRaw, runtimeBase);\n } catch (err) {\n devWarn('isActive computation error', err);\n return false;\n }\n });\n\n // Compute a normalized href for the inner anchor so middle-click / open-in-new-tab\n // uses a canonical absolute path (includes base and fragment). We keep using\n // props.to for router navigation so current behavior (literal `to`) remains.\n const hrefTarget = computed(() => {\n const raw = String(props.to || '');\n // Block obviously dangerous javascript: URIs from becoming clickable\n // hrefs. See isDangerousScheme for rationale.\n if (isDangerousScheme(raw)) return null;\n\n // Preserve absolute URLs with a scheme (http:, mailto:, data:, etc.)\n // and protocol-relative URLs that begin with `//`.\n if (isAbsoluteUrl(raw)) return raw;\n\n // Split fragment and query explicitly so both are preserved.\n const [pathWithQuery, frag] = raw.split('#');\n const [pathOnly, query] = (pathWithQuery || '').split('?');\n\n // Read base dynamically from the current router instance so repeated\n // calls to initRouter (tests) do not leave a stale captured value.\n const runtimeBase = activeRouterProxy.base ?? '';\n // If the provided path already contains the runtime base, strip it to\n // avoid duplicating e.g. '/app/app/about'. Keep a fallback of '/'.\n // Use more robust base removal that handles normalization edge cases.\n let candidate = pathOnly || '/';\n if (runtimeBase && runtimeBase !== '/') {\n // Normalize both base and candidate to ensure consistent comparison\n const normalizedBase = normalizePathForRoute(runtimeBase);\n const normalizedCandidate = normalizePathForRoute(candidate);\n if (normalizedCandidate.startsWith(normalizedBase)) {\n candidate = normalizedCandidate.slice(normalizedBase.length) || '/';\n } else {\n candidate = normalizedCandidate;\n }\n }\n const norm = normalizePathForRoute(candidate || '/');\n return (\n runtimeBase +\n norm +\n (query ? '?' + query : '') +\n (frag ? '#' + frag : '')\n );\n });\n\n // Build user classes reactively from the host `class` attribute prop.\n // We intentionally apply classes to the inner element so the consumer\n // can style the link via `class=\"...\"`.\n const userClasses = computed(() => {\n const rawHost =\n (hostClassRef && hostClassRef.value) || (props.class as string) || '';\n const list = rawHost.split(/\\s+/).filter(Boolean);\n const map: Record<string, boolean> = {};\n for (const c of list) map[c] = true;\n return map;\n });\n\n const classObject = computed(() => ({\n ...userClasses.value,\n [(props.activeClass as string) || 'active']: isActive.value,\n [(props.exactActiveClass as string) || 'exact-active']:\n isExactActive.value,\n }));\n\n // Compute a final class string (template accepts object or string; we\n // convert to string to safely include host classes and conditionals).\n const classString = computed(() =>\n Object.keys(classObject.value)\n .filter((k) => classObject.value[k])\n .join(' '),\n );\n\n const tagName = computed(() => (props.tag as string) || 'a');\n const isButton = computed(() => tagName.value === 'button');\n // Instead of pre-building attribute fragments as strings (which can\n // accidentally inject invalid attribute names into the template and\n // cause DOMExceptions), compute simple booleans/values and apply\n // attributes explicitly in the template below.\n // Return null when not exact so the attribute is omitted from the DOM\n const ariaCurrentValue = computed<null | string>(() =>\n isExactActive.value ? (props.ariaCurrentValue as string) : null,\n );\n const isDisabled = computed(() => !!props.disabled);\n // External should only apply to anchor tags (links). Make the check explicit.\n // Detect absolute/protocol-relative URLs as external even if the prop\n // wasn't explicitly set by the caller. Only apply to anchor tags.\n const isExternal = computed(() => {\n const toStr = String(props.to || '');\n const looksAbsolute = isAbsoluteUrl(toStr);\n return (looksAbsolute || !!props.external) && tagName.value === 'a';\n });\n\n // Inline style from host `style` attribute.\n const inlineStyle = computed(\n () =>\n (hostStyleRef && hostStyleRef.value) || (props.style as string) || '',\n );\n\n const navigate = (e: MouseEvent) => {\n // Respect pre-handled events, non-left clicks, and modifier keys so\n // default browser behaviors (open-in-new-tab, context menu) work.\n if (\n e.defaultPrevented ||\n e.button !== 0 ||\n e.metaKey ||\n e.altKey ||\n e.ctrlKey ||\n e.shiftKey\n )\n return;\n\n if (isDisabled.value) {\n // Prevent navigation and let assistive tech see disabled state\n e.preventDefault();\n return;\n }\n\n // Block dangerous javascript: URIs explicitly to avoid accidental XSS\n const _targetRaw = String(props.to || '');\n if (isDangerousScheme(_targetRaw)) {\n try {\n e.preventDefault();\n } catch {\n /* swallow */\n }\n devWarn('Blocked unsafe javascript: URI in router-link.to');\n return;\n }\n\n // If this is an external anchor, allow default browser behavior\n if (isExternal.value) return;\n\n e.preventDefault();\n if (props.replace) {\n activeRouterProxy.replace(props.to as string);\n } else {\n activeRouterProxy.push(props.to as string);\n }\n };\n\n return html`\n ${match()\n .when(\n isButton.value,\n html`\n <button\n part=\"button\"\n class=\"${classString.value}\"\n style=\"${inlineStyle.value || null}\"\n aria-current=\"${ariaCurrentValue.value}\"\n disabled=\"${isDisabled.value ? '' : null}\"\n aria-disabled=\"${isDisabled.value ? 'true' : null}\"\n tabindex=\"${isDisabled.value ? '-1' : null}\"\n @click=\"${navigate}\"\n >\n <slot></slot>\n </button>\n `,\n )\n .otherwise(html`\n <a\n part=\"link\"\n href=\"${isDisabled.value ? null : hrefTarget.value}\"\n class=\"${classString.value}\"\n style=\"${inlineStyle.value || null}\"\n aria-current=\"${ariaCurrentValue.value}\"\n aria-disabled=\"${isDisabled.value ? 'true' : null}\"\n tabindex=\"${isDisabled.value ? '-1' : null}\"\n target=\"${isExternal.value ? '_blank' : null}\"\n rel=\"${isExternal.value ? 'noopener noreferrer' : null}\"\n @click=\"${navigate}\"\n ><slot></slot\n ></a>\n `)\n .done()}\n `;\n });\n\n return router;\n}\n\n// Helper functions for SSR-safe active state computation\nexport function computeExactActive(\n currentPath: string,\n targetRaw: string,\n runtimeBase: string,\n): boolean {\n if (isAbsoluteUrl(targetRaw)) return false;\n\n const targetPathOnly = (targetRaw.split('#')[0] || '/').split('?')[0];\n let tgtCandidate = targetPathOnly;\n\n if (runtimeBase && runtimeBase !== '/') {\n const normalizedBase = normalizePathForRoute(runtimeBase);\n const normalizedTarget = normalizePathForRoute(tgtCandidate);\n if (normalizedTarget.startsWith(normalizedBase)) {\n tgtCandidate = normalizedTarget.slice(normalizedBase.length) || '/';\n } else {\n tgtCandidate = normalizedTarget;\n }\n }\n\n const cur = normalizePathForRoute(currentPath);\n const tgt = normalizePathForRoute(tgtCandidate);\n return cur === tgt;\n}\n\nexport function computeActive(\n currentPath: string,\n targetRaw: string,\n runtimeBase: string,\n): boolean {\n if (isAbsoluteUrl(targetRaw)) return false;\n\n const targetPathOnly = (targetRaw.split('#')[0] || '/').split('?')[0];\n let tgtCandidate = targetPathOnly;\n\n if (runtimeBase && runtimeBase !== '/') {\n const normalizedBase = normalizePathForRoute(runtimeBase);\n const normalizedTarget = normalizePathForRoute(tgtCandidate);\n if (normalizedTarget.startsWith(normalizedBase)) {\n tgtCandidate = normalizedTarget.slice(normalizedBase.length) || '/';\n } else {\n tgtCandidate = normalizedTarget;\n }\n }\n\n const cur = normalizePathForRoute(currentPath);\n const tgt = normalizePathForRoute(tgtCandidate);\n\n if (tgt === '/') return cur === '/';\n if (cur === tgt) return true;\n return cur.startsWith(tgt.endsWith('/') ? tgt : tgt + '/');\n}\n"],"names":["DEFAULT_SCROLL_CONFIG","parseQuery","search","serializeQuery","q","isDangerousScheme","s","isAbsoluteUrl","url","safeDecode","value","normalizePathForRoute","p","out","canonicalizeBase","base","normalized","compileCache","escapeSeg","seg","compileRoute","route","raw","routePath","segments","paramNames","regexParts","i","devWarn","name","paramMatch","isSplat","pattern","prefix","e","matchRoute","routes","path","incoming","compiled","regex","m","params","rawValue","findMatchedRoute","r","matchRouteSSR","pathname","MAX_COMPONENT_CACHE_SIZE","componentCache","loadingCache","clearComponentCache","evictLRUComponents","entries","toRemove","a","b","resolveRouteComponent","cached","isSSR","loadPromise","mod","component","err","errorMsg","devError","activeRouter","setActiveRouter","getActiveRouter","_proxyListeners","_proxyInnerUnsub","_rebindProxy","innerCalledSync","listener","activeRouterProxy","cur","flushDOMUpdates","rebindProxy","partial","currentState","frag","useRouter","config","initialUrl","scrollToFragment","canonicalBase","_scrollConfig","getLocation","initial","store","update","push","replaceFn","back","destroyFn","redirectTracker","MAX_REDIRECT_DEPTH","redirectDepth","runBeforeEnter","to","from","matched","result","redirectKey","runOnEnter","runAfterEnter","matchCache","MATCH_CACHE_SIZE","cachedMatchRoute","entriesToRemove","keys","cleanupScrollState","doScrollToElement","id","offset","element","rect","top","startScrollForNavigation","timeoutMs","resolve","resolved","timeoutId","rafHandle","startTime","safeResolve","attemptScroll","retryScroll","error","isNavigating","navigate","replace","performNavigation","parseNavigationPath","hashIndex","fragment","rawPath","qIndex","pathBeforeQuery","query","stripped","loc","match","beforeEnterResult","onEnterResult","qstr","href","current","fallbackRoute","fallbackMatch","recoveryError","routeList","pathSet","createStore","handlePopState","navigateSSR","initRouter","router","prevRouter","ctxRouter","getCurrentComponentContext","routerToUse","html","ref","unsubRouterView","useOnConnected","useOnDisconnected","comp","resolvedComp","props","useProps","stableCurrentPath","targetPath","ssrActiveStates","computeExactActive","computeActive","unsubRouterLink","useStyle","hostClassRef","hostStyleRef","syncCheckInterval","ctx","latestState","host","hc","hs","isExactActive","computed","runtimeBase","targetRaw","isActive","hrefTarget","pathWithQuery","pathOnly","candidate","normalizedBase","normalizedCandidate","norm","userClasses","list","map","c","classObject","classString","k","tagName","isButton","ariaCurrentValue","isDisabled","isExternal","toStr","inlineStyle","_targetRaw","currentPath","tgtCandidate","normalizedTarget","tgt"],"mappings":"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"}
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const T=require("./custom-elements-runtime.ssr.cjs.js");function H(t,r,c){if(!c)return t;if(t.trimStart().toLowerCase().startsWith("<html")||t.includes("</html>")){const o=r??"",d=t.startsWith("<!DOCTYPE")?t:`<!DOCTYPE html>${t}`;return o&&d.includes("</head>")?d.replace("</head>",`${o}</head>`):d}return`<!DOCTYPE html><html><head>${r??""}</head><body>${t}</body></html>`}function b(t,r){const c={dsd:!0,...r?.render},{head:u,document:o=!0}=r??{};return async(d,n)=>{try{const e=typeof t=="function"?await t(d):t,a=e!==null&&typeof e=="object"&&"vnode"in e,m=a?e.vnode:e,p=a?e.router:void 0,w=a?e.head:void 0,{htmlWithStyles:l}=T.renderToStringWithJITCSS(m,{...c,router:p}),y=[u,w].filter(Boolean).join(`
|
|
2
|
+
`)||void 0,h=H(l,y,o);n.setHeader("Content-Type","text/html; charset=utf-8"),n.end(h)}catch(e){try{n.setHeader("Content-Type","text/plain; charset=utf-8"),n.end("Internal Server Error")}catch{}throw e}}}function g(t,r){const c={dsd:!0,...r?.render},{head:u,document:o=!0}=r??{};return async(d,n)=>{try{const e=typeof t=="function"?await t(d):t,a=e!==null&&typeof e=="object"&&"vnode"in e,m=a?e.vnode:e,p=a?e.router:void 0,w=a?e.head:void 0,l=[u,w].filter(Boolean).join(`
|
|
3
|
+
`)||void 0;n.setHeader("Content-Type","text/html; charset=utf-8");const h=T.renderToStream(m,{...c,router:p}).getReader();if(n.write){n.setHeader("Transfer-Encoding","chunked"),o&&n.write(`<!DOCTYPE html><html><head>${l??""}</head><body>`);let s=!1;for(;!s;){const{value:i,done:f}=await h.read();i&&n.write(i),s=f}o?n.end("</body></html>"):n.end()}else{const s=[];let i=!1;for(;!i;){const{value:S,done:C}=await h.read();S&&s.push(S),i=C}const f=s.join(""),v=o?`<!DOCTYPE html><html><head>${l??""}</head><body>${f}</body></html>`:f;n.end(v)}}catch(e){try{n.setHeader("Content-Type","text/plain; charset=utf-8"),n.end("Internal Server Error")}catch{}throw e}}}exports.createSSRHandler=b;exports.createStreamingSSRHandler=g;
|
|
2
4
|
//# sourceMappingURL=custom-elements-runtime.ssr-middleware.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"custom-elements-runtime.ssr-middleware.cjs.js","sources":["../src/lib/ssr-middleware.ts"],"sourcesContent":["/**\n * SSR middleware helpers for Express, Fastify, Hono, and other Node.js HTTP frameworks.\n *\n * Provides two handler factories that wrap the SSR rendering pipeline and\n * emit a complete HTML document response. Both accept a static VNode **or**\n * a per-request factory function so route-specific data can be threaded into\n * the render tree.\n *\n * @example Express — static VNode\n * ```ts\n * import express from 'express';\n * import { createSSRHandler } from '@jasonshimmy/custom-elements-runtime/ssr-middleware';\n * import { html } from '@jasonshimmy/custom-elements-runtime';\n *\n * const app = express();\n * app.get('/', createSSRHandler(html`<my-app />`, {\n * render: { dsd: true, jit: { extendedColors: true } },\n * }));\n * ```\n *\n * @example Express — per-request factory\n * ```ts\n * app.get('*', createSSRHandler(\n * (req) => html`<my-app url=\"${req.url}\" />`,\n * { render: { dsd: true }, head: '<link rel=\"stylesheet\" href=\"/app.css\">' },\n * ));\n * ```\n *\n * @example Streaming variant\n * ```ts\n * app.get('*', createStreamingSSRHandler(\n * (req) => html`<my-app url=\"${req.url}\" />`,\n * ));\n * ```\n */\n\nimport { renderToStringWithJITCSS, renderToStream } from './ssr';\nimport type { VNode } from './runtime/types';\nimport type { RenderOptions } from './runtime/vdom-ssr';\nimport type { DSDRenderOptions } from './runtime/vdom-ssr-dsd';\nimport type { JITCSSOptions } from './runtime/style';\n\n// ---------------------------------------------------------------------------\n// Minimal framework-agnostic HTTP types\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal request interface compatible with Express, Fastify, Hono, and the\n * raw Node.js `IncomingMessage`. Extend or replace with your framework's\n * request type via the generic parameter on `createSSRHandler`.\n */\nexport interface MinimalRequest {\n url?: string;\n method?: string;\n headers?: Record<string, string | string[] | undefined>;\n}\n\n/**\n * Minimal response interface compatible with Express, Fastify, Hono, and the\n * raw Node.js `ServerResponse`. `write` is optional — handlers fall back to\n * buffering when it is absent.\n */\nexport interface MinimalResponse {\n setHeader(name: string, value: string): void;\n write?(chunk: string): boolean | void;\n end(data?: string): void;\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/**\n * Options for {@link createSSRHandler} and {@link createStreamingSSRHandler}.\n */\nexport interface SSRMiddlewareOptions {\n /**\n * Render options forwarded to `renderToStringWithJITCSS`.\n * Defaults to `{ dsd: true }` so DSD output is on by default.\n */\n render?: RenderOptions & DSDRenderOptions & { jit?: JITCSSOptions };\n /**\n * Additional HTML inserted at the end of the `<head>` tag.\n * Use this to inject `<link>`, `<script>`, `<meta>`, or `<title>` tags.\n */\n head?: string;\n /**\n * When `true` (default), the response is wrapped in a complete\n * `<!DOCTYPE html>` document shell. Set to `false` if you want to\n * assemble the document yourself and only need the rendered fragment.\n */\n document?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction wrapInDocument(\n htmlWithStyles: string,\n head: string | undefined,\n wrapDocument: boolean,\n): string {\n if (!wrapDocument) return htmlWithStyles;\n\n // If the rendered HTML already contains a root <html> tag, inject extra\n // head tags and prepend the DOCTYPE — do not double-wrap.\n if (\n htmlWithStyles.trimStart().toLowerCase().startsWith('<html') ||\n htmlWithStyles.includes('</html>')\n ) {\n const extra = head ?? '';\n const withDoctype = htmlWithStyles.startsWith('<!DOCTYPE')\n ? htmlWithStyles\n : `<!DOCTYPE html>${htmlWithStyles}`;\n if (extra) {\n return withDoctype.includes('</head>')\n ? withDoctype.replace('</head>', `${extra}</head>`)\n : withDoctype;\n }\n return withDoctype;\n }\n\n // Minimal shell\n const headContent = head ?? '';\n return `<!DOCTYPE html><html><head>${headContent}</head><body>${htmlWithStyles}</body></html>`;\n}\n\n// ---------------------------------------------------------------------------\n// Handler factories\n// ---------------------------------------------------------------------------\n\n/**\n * Create a request handler that SSR-renders a VNode tree and sends the full\n * HTML document as the response.\n *\n * Compatible with Express, Fastify, Hono, and any framework that uses an\n * `(req, res)` handler signature. The generic `Req` parameter lets you use\n * your framework's typed request object.\n *\n * @param vnodeOrFactory - A static {@link VNode} **or** a (possibly async)\n * factory function that receives the request and returns the VNode to render.\n * @param options - Render and document-shell options.\n *\n * @example\n * ```ts\n * app.get('*', createSSRHandler(\n * (req) => html`<my-app url=\"${req.url}\" />`,\n * { render: { dsd: true, jit: { extendedColors: true } } },\n * ));\n * ```\n */\nexport function createSSRHandler<Req extends MinimalRequest = MinimalRequest>(\n vnodeOrFactory: VNode | ((req: Req) => VNode | Promise<VNode>),\n options?: SSRMiddlewareOptions,\n): (req: Req, res: MinimalResponse) => Promise<void> {\n const renderOptions: RenderOptions &\n DSDRenderOptions & { jit?: JITCSSOptions } = {\n dsd: true,\n ...options?.render,\n };\n const { head, document: wrapDocument = true } = options ?? {};\n\n return async (req, res) => {\n try {\n const vnode =\n typeof vnodeOrFactory === 'function'\n ? await vnodeOrFactory(req)\n : vnodeOrFactory;\n\n const { htmlWithStyles } = renderToStringWithJITCSS(vnode, renderOptions);\n\n const body = wrapInDocument(htmlWithStyles, head, wrapDocument);\n\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.end(body);\n } catch (err) {\n // Ensure the response is always closed to prevent the request hanging.\n // Re-throw so the framework's error handler can set the proper status code.\n try {\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.end('Internal Server Error');\n } catch {\n // ignore secondary errors during error response\n }\n throw err;\n }\n };\n}\n\n/**\n * Create a request handler that SSR-renders a VNode tree and streams the HTML\n * response using chunked transfer encoding.\n *\n * Each chunk produced by the underlying {@link renderToStream} call is written\n * to the response as it becomes available, minimising Time-to-First-Byte.\n * The document shell preamble (`<!DOCTYPE html>…<body>`) is sent in the first\n * write so the browser can begin parsing immediately.\n *\n * @param vnodeOrFactory - A static {@link VNode} **or** a (possibly async)\n * factory function that receives the request and returns the VNode to render.\n * @param options - Render and document-shell options.\n *\n * @example\n * ```ts\n * app.get('*', createStreamingSSRHandler(\n * (req) => html`<my-app url=\"${req.url}\" />`,\n * { render: { dsd: true } },\n * ));\n * ```\n */\nexport function createStreamingSSRHandler<\n Req extends MinimalRequest = MinimalRequest,\n>(\n vnodeOrFactory: VNode | ((req: Req) => VNode | Promise<VNode>),\n options?: SSRMiddlewareOptions,\n): (req: Req, res: MinimalResponse) => Promise<void> {\n const renderOptions: RenderOptions &\n DSDRenderOptions & { jit?: JITCSSOptions } = {\n dsd: true,\n ...options?.render,\n };\n const { head, document: wrapDocument = true } = options ?? {};\n\n return async (req, res) => {\n try {\n const vnode =\n typeof vnodeOrFactory === 'function'\n ? await vnodeOrFactory(req)\n : vnodeOrFactory;\n\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n\n const stream = renderToStream(vnode, renderOptions);\n const reader = stream.getReader();\n\n if (res.write) {\n // Streaming path: pipe chunks directly to the response as they arrive.\n res.setHeader('Transfer-Encoding', 'chunked');\n if (wrapDocument) {\n res.write(`<!DOCTYPE html><html><head>${head ?? ''}</head><body>`);\n }\n let done = false;\n while (!done) {\n const { value, done: d } = await reader.read();\n if (value) res.write(value);\n done = d;\n }\n if (wrapDocument) {\n res.end('</body></html>');\n } else {\n res.end();\n }\n } else {\n // Buffered fallback: framework does not expose write(); collect and send as one response.\n const chunks: string[] = [];\n let done = false;\n while (!done) {\n const { value, done: d } = await reader.read();\n if (value) chunks.push(value);\n done = d;\n }\n const content = chunks.join('');\n const body = wrapDocument\n ? `<!DOCTYPE html><html><head>${head ?? ''}</head><body>${content}</body></html>`\n : content;\n res.end(body);\n }\n } catch (err) {\n // Ensure the response is always closed to prevent the request hanging.\n // Re-throw so the framework's error handler can set the proper status code.\n try {\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.end('Internal Server Error');\n } catch {\n // ignore secondary errors during error response\n }\n throw err;\n }\n };\n}\n"],"names":["wrapInDocument","htmlWithStyles","head","wrapDocument","extra","withDoctype","createSSRHandler","vnodeOrFactory","options","renderOptions","req","res","vnode","renderToStringWithJITCSS","body","err","createStreamingSSRHandler","reader","renderToStream","done","value","d","chunks","content"],"mappings":"wIAkGA,SAASA,EACPC,EACAC,EACAC,EACQ,CACR,GAAI,CAACA,EAAc,OAAOF,EAI1B,GACEA,EAAe,YAAY,cAAc,WAAW,OAAO,GAC3DA,EAAe,SAAS,SAAS,EACjC,CACA,MAAMG,EAAQF,GAAQ,GAChBG,EAAcJ,EAAe,WAAW,WAAW,EACrDA,EACA,kBAAkBA,CAAc,GACpC,OAAIG,GACKC,EAAY,SAAS,SAAS,EACjCA,EAAY,QAAQ,UAAW,GAAGD,CAAK,SAAS,EAG/CC,CACT,CAIA,MAAO,8BADaH,GAAQ,EACoB,gBAAgBD,CAAc,gBAChF,CA0BO,SAASK,EACdC,EACAC,EACmD,CACnD,MAAMC,EACyC,CAC7C,IAAK,GACL,GAAGD,GAAS,MAAA,EAER,CAAE,KAAAN,EAAM,SAAUC,EAAe,EAAA,EAASK,GAAW,CAAA,EAE3D,MAAO,OAAOE,EAAKC,IAAQ,CACzB,GAAI,CACF,MAAMC,EACJ,OAAOL,GAAmB,WACtB,MAAMA,EAAeG,CAAG,EACxBH,EAEA,CAAE,eAAAN,CAAA,EAAmBY,2BAAyBD,EAAOH,CAAa,EAElEK,EAAOd,EAAeC,EAAgBC,EAAMC,CAAY,EAE9DQ,EAAI,UAAU,eAAgB,0BAA0B,EACxDA,EAAI,IAAIG,CAAI,CACd,OAASC,EAAK,CAGZ,GAAI,CACFJ,EAAI,UAAU,eAAgB,2BAA2B,EACzDA,EAAI,IAAI,uBAAuB,CACjC,MAAQ,CAER,CACA,MAAMI,CACR,CACF,CACF,CAuBO,SAASC,EAGdT,EACAC,EACmD,CACnD,MAAMC,EACyC,CAC7C,IAAK,GACL,GAAGD,GAAS,MAAA,EAER,CAAE,KAAAN,EAAM,SAAUC,EAAe,EAAA,EAASK,GAAW,CAAA,EAE3D,MAAO,OAAOE,EAAKC,IAAQ,CACzB,GAAI,CACF,MAAMC,EACJ,OAAOL,GAAmB,WACtB,MAAMA,EAAeG,CAAG,EACxBH,EAENI,EAAI,UAAU,eAAgB,0BAA0B,EAGxD,MAAMM,EADSC,EAAAA,eAAeN,EAAOH,CAAa,EAC5B,UAAA,EAEtB,GAAIE,EAAI,MAAO,CAEbA,EAAI,UAAU,oBAAqB,SAAS,EACxCR,GACFQ,EAAI,MAAM,8BAA8BT,GAAQ,EAAE,eAAe,EAEnE,IAAIiB,EAAO,GACX,KAAO,CAACA,GAAM,CACZ,KAAM,CAAE,MAAAC,EAAO,KAAMC,GAAM,MAAMJ,EAAO,KAAA,EACpCG,GAAOT,EAAI,MAAMS,CAAK,EAC1BD,EAAOE,CACT,CACIlB,EACFQ,EAAI,IAAI,gBAAgB,EAExBA,EAAI,IAAA,CAER,KAAO,CAEL,MAAMW,EAAmB,CAAA,EACzB,IAAIH,EAAO,GACX,KAAO,CAACA,GAAM,CACZ,KAAM,CAAE,MAAAC,EAAO,KAAMC,GAAM,MAAMJ,EAAO,KAAA,EACpCG,GAAOE,EAAO,KAAKF,CAAK,EAC5BD,EAAOE,CACT,CACA,MAAME,EAAUD,EAAO,KAAK,EAAE,EACxBR,EAAOX,EACT,8BAA8BD,GAAQ,EAAE,gBAAgBqB,CAAO,iBAC/DA,EACJZ,EAAI,IAAIG,CAAI,CACd,CACF,OAASC,EAAK,CAGZ,GAAI,CACFJ,EAAI,UAAU,eAAgB,2BAA2B,EACzDA,EAAI,IAAI,uBAAuB,CACjC,MAAQ,CAER,CACA,MAAMI,CACR,CACF,CACF"}
|
|
1
|
+
{"version":3,"file":"custom-elements-runtime.ssr-middleware.cjs.js","sources":["../src/lib/ssr-middleware.ts"],"sourcesContent":["/**\n * SSR middleware helpers for Express, Fastify, Hono, and other Node.js HTTP frameworks.\n *\n * Provides two handler factories that wrap the SSR rendering pipeline and\n * emit a complete HTML document response. Both accept a static VNode **or**\n * a per-request factory function so route-specific data can be threaded into\n * the render tree.\n *\n * @example Express — static VNode\n * ```ts\n * import express from 'express';\n * import { createSSRHandler } from '@jasonshimmy/custom-elements-runtime/ssr-middleware';\n * import { html } from '@jasonshimmy/custom-elements-runtime';\n *\n * const app = express();\n * app.get('/', createSSRHandler(html`<my-app />`, {\n * render: { dsd: true, jit: { extendedColors: true } },\n * }));\n * ```\n *\n * @example Express — per-request factory\n * ```ts\n * app.get('*', createSSRHandler(\n * (req) => html`<my-app url=\"${req.url}\" />`,\n * { render: { dsd: true }, head: '<link rel=\"stylesheet\" href=\"/app.css\">' },\n * ));\n * ```\n *\n * @example Streaming variant\n * ```ts\n * app.get('*', createStreamingSSRHandler(\n * (req) => html`<my-app url=\"${req.url}\" />`,\n * ));\n * ```\n */\n\nimport { renderToStringWithJITCSS, renderToStream } from './ssr';\nimport type { VNode } from './runtime/types';\nimport type { RenderOptions } from './runtime/vdom-ssr';\nimport type { DSDRenderOptions } from './runtime/vdom-ssr-dsd';\nimport type { JITCSSOptions } from './runtime/style';\n\n/**\n * What a per-request factory may return.\n *\n * - Plain `VNode` — backward-compatible; no per-request router threading.\n * - `{ vnode, router? }` — the router instance is threaded through the render\n * context, making concurrent SSR requests safe (each render reads from its\n * own router, not the module-level `activeRouterProxy` singleton).\n * - `{ vnode, router?, head? }` — `head` is an HTML string injected into the\n * document `<head>` for this specific request (e.g. serialized loader data).\n * It is merged with the static `head` option passed to the handler factory.\n */\nexport type VnodeFactoryResult = VNode | { vnode: VNode; router?: unknown; head?: string };\n\n// ---------------------------------------------------------------------------\n// Minimal framework-agnostic HTTP types\n// ---------------------------------------------------------------------------\n\n/**\n * Minimal request interface compatible with Express, Fastify, Hono, and the\n * raw Node.js `IncomingMessage`. Extend or replace with your framework's\n * request type via the generic parameter on `createSSRHandler`.\n */\nexport interface MinimalRequest {\n url?: string;\n method?: string;\n headers?: Record<string, string | string[] | undefined>;\n}\n\n/**\n * Minimal response interface compatible with Express, Fastify, Hono, and the\n * raw Node.js `ServerResponse`. `write` is optional — handlers fall back to\n * buffering when it is absent.\n */\nexport interface MinimalResponse {\n setHeader(name: string, value: string): void;\n write?(chunk: string): boolean | void;\n end(data?: string): void;\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/**\n * Options for {@link createSSRHandler} and {@link createStreamingSSRHandler}.\n */\nexport interface SSRMiddlewareOptions {\n /**\n * Render options forwarded to `renderToStringWithJITCSS`.\n * Defaults to `{ dsd: true }` so DSD output is on by default.\n */\n render?: RenderOptions & DSDRenderOptions & { jit?: JITCSSOptions };\n /**\n * Additional HTML inserted at the end of the `<head>` tag.\n * Use this to inject `<link>`, `<script>`, `<meta>`, or `<title>` tags.\n */\n head?: string;\n /**\n * When `true` (default), the response is wrapped in a complete\n * `<!DOCTYPE html>` document shell. Set to `false` if you want to\n * assemble the document yourself and only need the rendered fragment.\n */\n document?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction wrapInDocument(\n htmlWithStyles: string,\n head: string | undefined,\n wrapDocument: boolean,\n): string {\n if (!wrapDocument) return htmlWithStyles;\n\n // If the rendered HTML already contains a root <html> tag, inject extra\n // head tags and prepend the DOCTYPE — do not double-wrap.\n if (\n htmlWithStyles.trimStart().toLowerCase().startsWith('<html') ||\n htmlWithStyles.includes('</html>')\n ) {\n const extra = head ?? '';\n const withDoctype = htmlWithStyles.startsWith('<!DOCTYPE')\n ? htmlWithStyles\n : `<!DOCTYPE html>${htmlWithStyles}`;\n if (extra) {\n return withDoctype.includes('</head>')\n ? withDoctype.replace('</head>', `${extra}</head>`)\n : withDoctype;\n }\n return withDoctype;\n }\n\n // Minimal shell\n const headContent = head ?? '';\n return `<!DOCTYPE html><html><head>${headContent}</head><body>${htmlWithStyles}</body></html>`;\n}\n\n// ---------------------------------------------------------------------------\n// Handler factories\n// ---------------------------------------------------------------------------\n\n/**\n * Create a request handler that SSR-renders a VNode tree and sends the full\n * HTML document as the response.\n *\n * Compatible with Express, Fastify, Hono, and any framework that uses an\n * `(req, res)` handler signature. The generic `Req` parameter lets you use\n * your framework's typed request object.\n *\n * @param vnodeOrFactory - A static {@link VNode} **or** a (possibly async)\n * factory function that receives the request and returns the VNode to render.\n * @param options - Render and document-shell options.\n *\n * @example\n * ```ts\n * app.get('*', createSSRHandler(\n * (req) => html`<my-app url=\"${req.url}\" />`,\n * { render: { dsd: true, jit: { extendedColors: true } } },\n * ));\n * ```\n */\nexport function createSSRHandler<Req extends MinimalRequest = MinimalRequest>(\n vnodeOrFactory:\n | VnodeFactoryResult\n | ((req: Req) => VnodeFactoryResult | Promise<VnodeFactoryResult>),\n options?: SSRMiddlewareOptions,\n): (req: Req, res: MinimalResponse) => Promise<void> {\n const renderOptions: RenderOptions &\n DSDRenderOptions & { jit?: JITCSSOptions } = {\n dsd: true,\n ...options?.render,\n };\n const { head, document: wrapDocument = true } = options ?? {};\n\n return async (req, res) => {\n try {\n const rawResult =\n typeof vnodeOrFactory === 'function'\n ? await vnodeOrFactory(req)\n : vnodeOrFactory;\n\n const isBundle =\n rawResult !== null &&\n typeof rawResult === 'object' &&\n 'vnode' in (rawResult as object);\n const vnode = isBundle\n ? (rawResult as { vnode: VNode }).vnode\n : (rawResult as VNode);\n const router = isBundle\n ? (rawResult as { vnode: VNode; router?: unknown }).router\n : undefined;\n const perRequestHead = isBundle\n ? (rawResult as { head?: string }).head\n : undefined;\n\n const { htmlWithStyles } = renderToStringWithJITCSS(vnode, { ...renderOptions, router });\n\n const mergedHead = [head, perRequestHead].filter(Boolean).join('\\n') || undefined;\n const body = wrapInDocument(htmlWithStyles, mergedHead, wrapDocument);\n\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.end(body);\n } catch (err) {\n // Ensure the response is always closed to prevent the request hanging.\n // Re-throw so the framework's error handler can set the proper status code.\n try {\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.end('Internal Server Error');\n } catch {\n // ignore secondary errors during error response\n }\n throw err;\n }\n };\n}\n\n/**\n * Create a request handler that SSR-renders a VNode tree and streams the HTML\n * response using chunked transfer encoding.\n *\n * Each chunk produced by the underlying {@link renderToStream} call is written\n * to the response as it becomes available, minimising Time-to-First-Byte.\n * The document shell preamble (`<!DOCTYPE html>…<body>`) is sent in the first\n * write so the browser can begin parsing immediately.\n *\n * @param vnodeOrFactory - A static {@link VNode} **or** a (possibly async)\n * factory function that receives the request and returns the VNode to render.\n * @param options - Render and document-shell options.\n *\n * @example\n * ```ts\n * app.get('*', createStreamingSSRHandler(\n * (req) => html`<my-app url=\"${req.url}\" />`,\n * { render: { dsd: true } },\n * ));\n * ```\n */\nexport function createStreamingSSRHandler<\n Req extends MinimalRequest = MinimalRequest,\n>(\n vnodeOrFactory:\n | VnodeFactoryResult\n | ((req: Req) => VnodeFactoryResult | Promise<VnodeFactoryResult>),\n options?: SSRMiddlewareOptions,\n): (req: Req, res: MinimalResponse) => Promise<void> {\n const renderOptions: RenderOptions &\n DSDRenderOptions & { jit?: JITCSSOptions } = {\n dsd: true,\n ...options?.render,\n };\n const { head, document: wrapDocument = true } = options ?? {};\n\n return async (req, res) => {\n try {\n const rawResult =\n typeof vnodeOrFactory === 'function'\n ? await vnodeOrFactory(req)\n : vnodeOrFactory;\n\n const isBundle =\n rawResult !== null &&\n typeof rawResult === 'object' &&\n 'vnode' in (rawResult as object);\n const vnode = isBundle\n ? (rawResult as { vnode: VNode }).vnode\n : (rawResult as VNode);\n const router = isBundle\n ? (rawResult as { vnode: VNode; router?: unknown }).router\n : undefined;\n const perRequestHead = isBundle\n ? (rawResult as { head?: string }).head\n : undefined;\n\n const mergedHead = [head, perRequestHead].filter(Boolean).join('\\n') || undefined;\n\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n\n const stream = renderToStream(vnode, { ...renderOptions, router });\n const reader = stream.getReader();\n\n if (res.write) {\n // Streaming path: pipe chunks directly to the response as they arrive.\n res.setHeader('Transfer-Encoding', 'chunked');\n if (wrapDocument) {\n res.write(`<!DOCTYPE html><html><head>${mergedHead ?? ''}</head><body>`);\n }\n let done = false;\n while (!done) {\n const { value, done: d } = await reader.read();\n if (value) res.write(value);\n done = d;\n }\n if (wrapDocument) {\n res.end('</body></html>');\n } else {\n res.end();\n }\n } else {\n // Buffered fallback: framework does not expose write(); collect and send as one response.\n const chunks: string[] = [];\n let done = false;\n while (!done) {\n const { value, done: d } = await reader.read();\n if (value) chunks.push(value);\n done = d;\n }\n const content = chunks.join('');\n const body = wrapDocument\n ? `<!DOCTYPE html><html><head>${mergedHead ?? ''}</head><body>${content}</body></html>`\n : content;\n res.end(body);\n }\n } catch (err) {\n // Ensure the response is always closed to prevent the request hanging.\n // Re-throw so the framework's error handler can set the proper status code.\n try {\n res.setHeader('Content-Type', 'text/plain; charset=utf-8');\n res.end('Internal Server Error');\n } catch {\n // ignore secondary errors during error response\n }\n throw err;\n }\n };\n}\n"],"names":["wrapInDocument","htmlWithStyles","head","wrapDocument","extra","withDoctype","createSSRHandler","vnodeOrFactory","options","renderOptions","req","res","rawResult","isBundle","vnode","router","perRequestHead","renderToStringWithJITCSS","mergedHead","body","err","createStreamingSSRHandler","reader","renderToStream","done","value","d","chunks","content"],"mappings":"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"}
|