stx-router 0.2.8
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/LICENSE.md +21 -0
- package/README.md +233 -0
- package/dist/client.d.ts +19 -0
- package/dist/codegen.d.ts +2 -0
- package/dist/file-router.d.ts +12 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +887 -0
- package/dist/index.js.map +16 -0
- package/dist/matcher.d.ts +3 -0
- package/dist/middleware.d.ts +28 -0
- package/dist/named-routes.d.ts +10 -0
- package/dist/nested-layouts.d.ts +1 -0
- package/dist/types.d.ts +97 -0
- package/package.json +50 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/file-router.ts", "../src/codegen.ts", "../src/matcher.ts", "../src/nested-layouts.ts", "../src/named-routes.ts", "../src/middleware.ts", "../src/client.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"import fs from 'node:fs'\nimport path from 'node:path'\nimport type { Route, RouteMatch, RouterConfig } from './types'\nimport { generateRouteTypes } from './codegen'\nimport { filePathToPattern, patternToRegex } from './matcher'\nimport { resolveLayoutChain } from './nested-layouts'\n\nfunction scanDirectory(dir: string, extensions: string[]): string[] {\n const files: string[] = []\n\n if (!fs.existsSync(dir)) {\n return files\n }\n\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name)\n\n if (entry.isDirectory()) {\n if (entry.name.startsWith('.')) {\n continue\n }\n files.push(...scanDirectory(fullPath, extensions))\n }\n else if (entry.isFile()) {\n const ext = path.extname(entry.name)\n if (extensions.includes(ext)) {\n // Skip layout files from being routes themselves\n if (entry.name.startsWith('_') && entry.name !== '_layout.stx') {\n continue\n }\n // Don't register _layout.stx as a route\n if (entry.name === '_layout.stx') {\n continue\n }\n files.push(fullPath)\n }\n }\n }\n\n return files\n}\n\nexport class Router {\n routes: Route[]\n private pagesDir: string\n private config: RouterConfig\n\n constructor(baseDir: string, config: RouterConfig = {}) {\n this.config = config\n this.pagesDir = path.resolve(baseDir, config.pagesDir || 'pages')\n const extensions = config.extensions || ['.stx']\n\n const files = scanDirectory(this.pagesDir, extensions)\n\n this.routes = files.map((filePath) => {\n const pattern = filePathToPattern(filePath, this.pagesDir)\n const { regex, params } = patternToRegex(pattern)\n const layouts = config.layouts !== false ? resolveLayoutChain(filePath, this.pagesDir) : []\n\n return {\n pattern,\n regex,\n params,\n filePath,\n isDynamic: params.length > 0,\n layout: layouts.length > 0 ? layouts[layouts.length - 1] : undefined,\n }\n })\n\n // Sort: static before dynamic, more segments first\n this.routes.sort((a, b) => {\n if (!a.isDynamic && b.isDynamic) return -1\n if (a.isDynamic && !b.isDynamic) return 1\n const aSegments = a.pattern.split('/').length\n const bSegments = b.pattern.split('/').length\n if (aSegments !== bSegments) return bSegments - aSegments\n return a.pattern.localeCompare(b.pattern)\n })\n\n // Generate type declarations\n const stxDir = path.join(baseDir, '.stx')\n generateRouteTypes(this.routes, stxDir)\n }\n\n match(pathname: string): RouteMatch | null {\n const normalizedPath = pathname === '' ? '/' : pathname\n\n for (const route of this.routes) {\n const m = normalizedPath.match(route.regex)\n if (m) {\n const params: Record<string, string> = {}\n route.params.forEach((name, index) => {\n params[name] = m[index + 1]\n })\n return { route, params }\n }\n }\n\n return null\n }\n\n resolve(name: string, params?: Record<string, string>): string {\n const route = this.routes.find(r => r.pattern === name || r.filePath.includes(name))\n if (!route) return '#not-found'\n\n let resolved = route.pattern\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n resolved = resolved.replace(`:${key}`, encodeURIComponent(value))\n }\n }\n return resolved\n }\n\n addRoute(route: Route): void {\n this.routes.push(route)\n this.routes.sort((a, b) => {\n if (!a.isDynamic && b.isDynamic) return -1\n if (a.isDynamic && !b.isDynamic) return 1\n return a.pattern.localeCompare(b.pattern)\n })\n }\n\n getLayout(route: Route): string | null {\n return route.layout ?? null\n }\n}\n\nexport function createRouter(baseDir: string, config?: RouterConfig): Router {\n return new Router(baseDir, config)\n}\n\nexport function findErrorPage(pagesDir: string, statusCode: number): string | null {\n const candidates = [`${statusCode}.stx`, 'error.stx']\n for (const candidate of candidates) {\n const filePath = path.join(pagesDir, candidate)\n if (fs.existsSync(filePath)) return filePath\n }\n return null\n}\n\nexport function formatRoutes(routes: Route[], baseDir: string): string[] {\n return routes.map((route) => {\n const relativePath = path.relative(baseDir, route.filePath)\n const dynamicLabel = route.isDynamic ? ' (dynamic)' : ''\n return `${route.pattern} → ${relativePath}${dynamicLabel}`\n })\n}\n",
|
|
6
|
+
"import fs from 'node:fs'\nimport path from 'node:path'\nimport type { Route } from './types'\n\nexport function generateRouteTypes(routes: Route[], outputDir: string): void {\n const lines = [\n '// Auto-generated by STX - do not edit',\n 'declare module \"stx/routes\" {',\n ' interface RouteMap {',\n ]\n\n for (const route of routes) {\n const paramEntries: string[] = []\n for (const p of route.params) {\n const type = route.pattern.includes(`:${p}*`) ? 'string[]' : 'string'\n paramEntries.push(`${p}: ${type}`)\n }\n const paramsStr = paramEntries.join('; ')\n lines.push(` '${route.pattern}': { ${paramsStr} }`)\n }\n\n lines.push(' }', '}', '')\n\n fs.mkdirSync(outputDir, { recursive: true })\n fs.writeFileSync(path.join(outputDir, 'route-types.d.ts'), lines.join('\\n'))\n}\n",
|
|
7
|
+
"import path from 'node:path'\n\nexport function filePathToPattern(filePath: string, pagesDir: string): string {\n const relativePath = path.relative(pagesDir, filePath)\n let route = relativePath.replace(/\\.(stx|md)$/, '')\n\n route = route.split(path.sep).join('/')\n\n if (route === 'index') {\n return '/'\n }\n if (route.endsWith('/index')) {\n route = route.slice(0, -6)\n }\n\n // Convert [[param]] to :param? (optional) — BEFORE required params\n route = route.replace(/\\[\\[([^\\]]+)\\]\\]/g, ':$1?')\n\n // Convert [param] to :param\n route = route.replace(/\\[([^\\]]+)\\]/g, ':$1')\n\n // Convert [...param] to :param* (catch-all)\n route = route.replace(/:\\.\\.\\.([^/]+)/g, ':$1*')\n\n return `/${route}`\n}\n\nexport function patternToRegex(pattern: string): { regex: RegExp, params: string[] } {\n const params: string[] = []\n\n let regexStr = pattern.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n\n // Handle optional params (/:param?)\n regexStr = regexStr.replace(/\\/:([^/]+)\\?/g, (_, name) => {\n params.push(name)\n return '(?:/([^/]+))?'\n })\n\n // Handle catch-all params (:param*)\n regexStr = regexStr.replace(/:([^/]+)\\*/g, (_, name) => {\n params.push(name)\n return '(.+)'\n })\n\n // Handle regular params (:param)\n regexStr = regexStr.replace(/:([^/]+)/g, (_, name) => {\n params.push(name)\n return '([^/]+)'\n })\n\n regexStr = `^${regexStr}$`\n\n return { regex: new RegExp(regexStr), params }\n}\n\nexport function matchRoute(pathname: string, routes: { pattern: string, regex: RegExp, params: string[] }[]): { route: typeof routes[0], params: Record<string, string> } | null {\n const normalizedPath = pathname === '' ? '/' : pathname\n\n for (const route of routes) {\n const match = normalizedPath.match(route.regex)\n if (match) {\n const params: Record<string, string> = {}\n route.params.forEach((name, index) => {\n params[name] = match[index + 1]\n })\n return { route, params }\n }\n }\n\n return null\n}\n",
|
|
8
|
+
"import fs from 'node:fs'\nimport path from 'node:path'\n\nexport function resolveLayoutChain(routeFilePath: string, pagesDir: string): string[] {\n const layouts: string[] = []\n let dir = path.dirname(routeFilePath)\n\n // Walk up from the route's directory to the pages root, collecting _layout.stx files\n while (dir.startsWith(pagesDir) || dir === pagesDir) {\n const layoutFile = path.join(dir, '_layout.stx')\n if (fs.existsSync(layoutFile)) {\n layouts.unshift(layoutFile) // Prepend so root layout is first\n }\n\n if (dir === pagesDir) break\n dir = path.dirname(dir)\n }\n\n return layouts\n}\n",
|
|
9
|
+
"interface RouteDefinition {\n path: string\n name?: string\n params?: Record<string, any>\n}\n\nconst routes: Record<string, RouteDefinition> = {}\nlet appUrl: string = ''\n\nexport function setAppUrl(url: string): void {\n appUrl = url.replace(/\\/$/, '')\n}\n\nexport function defineRoute(name: string, routePath: string, params: Record<string, any> = {}): void {\n routes[name] = { path: routePath, name, params }\n}\n\nexport function defineRoutes(routeDefinitions: Record<string, string | RouteDefinition>): void {\n for (const [name, definition] of Object.entries(routeDefinitions)) {\n if (typeof definition === 'string') {\n routes[name] = { path: definition, name }\n }\n else {\n routes[name] = { ...definition, name }\n }\n }\n}\n\nexport function route(\n name: string,\n params: Record<string, any> = {},\n absolute = false,\n): string {\n const r = routes[name]\n\n if (!r) {\n console.warn(`Route [${name}] not defined.`)\n return '#undefined-route'\n }\n\n const mergedParams = { ...r.params, ...params }\n let routePath = r.path\n\n routePath = routePath.replace(/:(\\w+)/g, (_, paramName) => {\n const value = mergedParams[paramName]\n\n if (value === undefined) {\n console.warn(`Missing parameter [${paramName}] for route [${name}].`)\n return `:${paramName}`\n }\n\n delete mergedParams[paramName]\n return encodeURIComponent(String(value))\n })\n\n const remainingParams = Object.entries(mergedParams)\n if (remainingParams.length > 0) {\n const queryString = remainingParams\n .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)\n .join('&')\n\n routePath += (routePath.includes('?') ? '&' : '?') + queryString\n }\n\n return absolute && appUrl ? `${appUrl}${routePath}` : routePath\n}\n\nexport function resetRoutes(): void {\n for (const key of Object.keys(routes)) {\n delete routes[key]\n }\n appUrl = ''\n}\n",
|
|
10
|
+
"import fs from 'node:fs'\nimport path from 'node:path'\nimport type {\n AbortNavigationResult,\n CookieManager,\n CookieOptions,\n MiddlewareContext,\n MiddlewareMode,\n MiddlewareOptions,\n MiddlewareResult,\n NavigateToOptions,\n NavigateToResult,\n NavigationError,\n NavigationResult,\n RouteLocation,\n RouteMiddlewareDefinition,\n RouteMiddlewareHandler,\n StorageManager,\n} from './types'\n\n// =============================================================================\n// Navigation Helpers\n// =============================================================================\n\nexport function navigateTo(navPath: string, options: NavigateToOptions = {}): NavigateToResult {\n return {\n type: 'redirect',\n path: navPath,\n options: {\n replace: options.replace ?? false,\n external: options.external ?? false,\n redirectCode: options.redirectCode ?? 302,\n },\n }\n}\n\nexport function abortNavigation(error: string | NavigationError): AbortNavigationResult {\n const normalizedError: NavigationError\n = typeof error === 'string' ? { statusCode: 500, message: error } : error\n\n return {\n type: 'abort',\n error: normalizedError,\n }\n}\n\n// =============================================================================\n// Middleware Definition\n// =============================================================================\n\nexport function defineMiddleware(\n handler: RouteMiddlewareHandler,\n options: MiddlewareOptions = {},\n): RouteMiddlewareDefinition {\n return {\n handler,\n mode: options.mode ?? 'universal',\n }\n}\n\n// =============================================================================\n// Cookie Manager\n// =============================================================================\n\nfunction parseCookies(cookieHeader: string): Record<string, string> {\n const cookies: Record<string, string> = {}\n if (!cookieHeader) return cookies\n\n const pairs = cookieHeader.split(';')\n for (const pair of pairs) {\n const [name, ...rest] = pair.split('=')\n if (name) {\n const key = name.trim()\n const value = rest.join('=').trim()\n if (key) {\n cookies[key] = decodeURIComponent(value)\n }\n }\n }\n return cookies\n}\n\nfunction serializeCookie(name: string, value: string, options: CookieOptions = {}): string {\n let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`\n\n if (options.expires) {\n const expires\n = typeof options.expires === 'number'\n ? new Date(Date.now() + options.expires * 1000)\n : options.expires\n cookie += `; Expires=${expires.toUTCString()}`\n }\n\n if (options.path) cookie += `; Path=${options.path}`\n if (options.domain) cookie += `; Domain=${options.domain}`\n if (options.secure) cookie += '; Secure'\n if (options.httpOnly) cookie += '; HttpOnly'\n if (options.sameSite) cookie += `; SameSite=${options.sameSite}`\n\n return cookie\n}\n\nexport function createServerCookieManager(\n request: Request,\n responseHeaders: Headers,\n): CookieManager {\n const cookieHeader = request.headers.get('cookie') || ''\n const cookies = parseCookies(cookieHeader)\n\n return {\n get(name: string): string | undefined {\n return cookies[name]\n },\n set(name: string, value: string, options: CookieOptions = {}): void {\n cookies[name] = value\n responseHeaders.append('Set-Cookie', serializeCookie(name, value, options))\n },\n delete(name: string): void {\n delete cookies[name]\n responseHeaders.append(\n 'Set-Cookie',\n serializeCookie(name, '', { expires: new Date(0), path: '/' }),\n )\n },\n getAll(): Record<string, string> {\n return { ...cookies }\n },\n }\n}\n\nexport function createClientCookieManager(): CookieManager {\n return {\n get(name: string): string | undefined {\n if (typeof document === 'undefined') return undefined\n const cookies = parseCookies(document.cookie)\n return cookies[name]\n },\n set(name: string, value: string, options: CookieOptions = {}): void {\n if (typeof document === 'undefined') return\n document.cookie = serializeCookie(name, value, options)\n },\n delete(name: string): void {\n if (typeof document === 'undefined') return\n document.cookie = serializeCookie(name, '', { expires: new Date(0), path: '/' })\n },\n getAll(): Record<string, string> {\n if (typeof document === 'undefined') return {}\n return parseCookies(document.cookie)\n },\n }\n}\n\n// =============================================================================\n// Storage Manager\n// =============================================================================\n\nexport function createStorageManager(): StorageManager {\n const available\n = typeof window !== 'undefined' && typeof window.localStorage !== 'undefined'\n\n return {\n get(key: string): string | null {\n if (!available) return null\n try { return window.localStorage.getItem(key) }\n catch { return null }\n },\n set(key: string, value: string): void {\n if (!available) return\n try { window.localStorage.setItem(key, value) }\n catch { /* storage full or blocked */ }\n },\n remove(key: string): void {\n if (!available) return\n try { window.localStorage.removeItem(key) }\n catch { /* ignore */ }\n },\n isAvailable(): boolean {\n return available\n },\n }\n}\n\n// =============================================================================\n// Middleware Registry\n// =============================================================================\n\nconst middlewareRegistry = new Map<string, RouteMiddlewareDefinition>()\n\nexport function registerMiddleware(name: string, middleware: RouteMiddlewareDefinition): void {\n middlewareRegistry.set(name, middleware)\n}\n\nexport function getMiddleware(name: string): RouteMiddlewareDefinition | undefined {\n return middlewareRegistry.get(name)\n}\n\nexport function hasMiddleware(name: string): boolean {\n return middlewareRegistry.has(name)\n}\n\nexport function clearMiddleware(): void {\n middlewareRegistry.clear()\n}\n\nexport function getMiddlewareNames(): string[] {\n return Array.from(middlewareRegistry.keys())\n}\n\n// =============================================================================\n// Middleware Loading\n// =============================================================================\n\nexport async function loadMiddlewareFromDirectory(\n baseDir: string,\n middlewareDir: string = 'middleware',\n): Promise<void> {\n const fullPath = path.resolve(baseDir, middlewareDir)\n\n if (!fs.existsSync(fullPath)) {\n return\n }\n\n const files = fs.readdirSync(fullPath)\n\n for (const file of files) {\n if (!file.endsWith('.ts') && !file.endsWith('.js')) continue\n if (file.includes('.test.') || file.includes('.spec.')) continue\n\n const name = file.replace(/\\.(ts|js)$/, '')\n const filePath = path.join(fullPath, file)\n\n try {\n const mod = await import(filePath)\n const mw = mod.default\n\n if (mw && typeof mw.handler === 'function') {\n registerMiddleware(name, mw)\n }\n else if (typeof mw === 'function') {\n registerMiddleware(name, { handler: mw, mode: 'universal' })\n }\n }\n catch (error) {\n console.warn(`Failed to load middleware '${name}' from ${filePath}:`, error)\n }\n }\n}\n\n// =============================================================================\n// Middleware Context & Execution\n// =============================================================================\n\nfunction parseQuery(search: string): Record<string, string> {\n const query: Record<string, string> = {}\n if (!search) return query\n\n const params = new URLSearchParams(search)\n for (const [key, value] of params) {\n query[key] = value\n }\n return query\n}\n\nexport function createRouteLocation(\n pathname: string,\n params: Record<string, string>,\n meta: Record<string, unknown>,\n search: string = '',\n): RouteLocation {\n return {\n path: pathname,\n params,\n query: parseQuery(search),\n fullPath: search ? `${pathname}?${search}` : pathname,\n meta,\n }\n}\n\nexport function createMiddlewareContext(\n to: RouteLocation,\n from: RouteLocation | null,\n request?: Request,\n): MiddlewareContext {\n const isServer = typeof window === 'undefined'\n const isClient = !isServer\n const responseHeaders = new Headers()\n\n return {\n to,\n from,\n isClient,\n isServer,\n cookies: isServer && request\n ? createServerCookieManager(request, responseHeaders)\n : createClientCookieManager(),\n storage: createStorageManager(),\n state: {},\n request,\n responseHeaders,\n }\n}\n\nexport async function runMiddleware(\n middlewareNames: string | string[],\n context: MiddlewareContext,\n): Promise<MiddlewareResult> {\n const names = Array.isArray(middlewareNames) ? middlewareNames : [middlewareNames]\n const isServer = context.isServer\n\n for (const name of names) {\n const middleware = getMiddleware(name)\n\n if (!middleware) {\n console.warn(`Middleware '${name}' not found`)\n continue\n }\n\n if (middleware.mode === 'server' && !isServer) continue\n if (middleware.mode === 'client' && isServer) continue\n\n try {\n const result = await middleware.handler(context)\n\n if (result) {\n if (result.type === 'redirect') {\n return {\n passed: false,\n redirect: result,\n state: context.state,\n responseHeaders: context.responseHeaders,\n }\n }\n\n if (result.type === 'abort') {\n return {\n passed: false,\n abort: result,\n state: context.state,\n responseHeaders: context.responseHeaders,\n }\n }\n }\n }\n catch (error) {\n console.error(`Error in middleware '${name}':`, error)\n return {\n passed: false,\n abort: {\n type: 'abort',\n error: {\n statusCode: 500,\n message: error instanceof Error ? error.message : 'Middleware error',\n },\n },\n state: context.state,\n responseHeaders: context.responseHeaders,\n }\n }\n }\n\n return {\n passed: true,\n state: context.state,\n responseHeaders: context.responseHeaders,\n }\n}\n",
|
|
11
|
+
"/**\n * STX Router - Canonical SPA Router\n *\n * Single source of truth for client-side navigation.\n * Injected via @stxRouter directive or auto-loaded with the signals runtime.\n *\n * Features:\n * - Click interception for internal links\n * - History API pushState navigation\n * - View Transitions API with CSS fade fallback\n * - <head> style swapping (prevents unstyled flash)\n * - Smart script filtering (skip signals runtime, layout guards)\n * - Page prefetching on hover\n * - Response caching (5-minute TTL)\n * - Active link class management (data-stx-link)\n * - Loading indicator bar\n * - Configurable via window.STX_ROUTER_OPTIONS or window.__stxRouterConfig\n */\nexport function getRouterScript(): string {\n return `\n;(function(){\n 'use strict';\n if(window.__stxRouter)return;\n\n // ── Configuration ──\n var defaults={container:'main',loadingClass:'stx-navigating',viewTransitions:true,cache:true,scrollToTop:true,prefetch:true};\n var o=Object.assign({},defaults,window.__stxRouterConfig||{},window.STX_ROUTER_OPTIONS||{});\n var containerSel=o.container;\n\n var cache={};\n var prefetching={};\n var isNavigating=false;\n\n function getContainer(){\n return document.querySelector(containerSel)||document.querySelector('[data-stx-content]')||document.querySelector('main');\n }\n\n // ── Navigation ──\n function navigate(url,pushState){\n if(isNavigating)return;\n var t=new URL(url,location.origin);\n\n // Different origin → full navigation\n if(t.origin!==location.origin){location.href=url;return}\n\n // Hash-only navigation on same page\n if(t.pathname===location.pathname&&t.hash){\n if(pushState!==false)history.pushState({},'',t.href);\n var el=document.querySelector(t.hash);\n if(el)el.scrollIntoView({behavior:'smooth'});\n return;\n }\n\n // Same page, no hash → skip\n if(t.href===location.href&&!t.hash)return;\n\n isNavigating=true;\n document.body.classList.add(o.loadingClass);\n\n var targetHref=t.href;\n var targetPath=t.pathname;\n var targetHash=t.hash;\n\n function done(){isNavigating=false;document.body.classList.remove(o.loadingClass)}\n\n if(o.cache&&cache[targetPath]){\n swap(cache[targetPath],targetPath,pushState,targetHash);\n done();\n }else{\n fetch(url,{headers:{'X-STX-Router':'true','Accept':'text/html'}}).then(function(r){\n if(!r.ok)throw new Error(r.status);\n return r.text();\n }).then(function(html){\n if(o.cache)cache[targetPath]=html;\n swap(html,targetPath,pushState,targetHash);\n }).catch(function(){\n location.href=url;\n }).finally(done);\n }\n }\n\n function swap(html,url,pushState,hash){\n var parser=new DOMParser();\n var doc=parser.parseFromString(html,'text/html');\n var newContent=doc.querySelector(containerSel)||doc.querySelector('[data-stx-content]')||doc.querySelector('main');\n var currentContent=getContainer();\n if(!newContent||!currentContent){location.href=url;return}\n\n // Clean up existing signals/effects\n if(window.stx&&window.stx._cleanupContainer){\n window.stx._cleanupContainer(currentContent);\n }\n\n function doSwap(){\n // ── Swap <head> styles ──\n // Inject new styles FIRST, then remove old to prevent unstyled flash\n var keepIds={'stx-view-transitions':1,'stx-r-css':1};\n var curStyles=document.querySelectorAll('head style');\n var newStyles=doc.querySelectorAll('head style');\n\n var incoming=[];\n newStyles.forEach(function(s){\n if(!keepIds[s.id]){\n var ns=document.createElement('style');\n ns.textContent=s.textContent;\n ns.setAttribute('data-stx-incoming','');\n if(s.getAttribute('data-crosswind'))ns.setAttribute('data-crosswind',s.getAttribute('data-crosswind'));\n document.head.appendChild(ns);\n incoming.push(ns);\n }\n });\n\n // Remove old styles (except persistent ones and incoming)\n curStyles.forEach(function(s){\n if(!keepIds[s.id]&&!s.hasAttribute('data-stx-incoming'))s.remove();\n });\n\n incoming.forEach(function(s){s.removeAttribute('data-stx-incoming')});\n\n // ── Swap main content ──\n currentContent.innerHTML=newContent.innerHTML;\n\n // ── Load new external <head> scripts ──\n var loadedSrcs={};\n document.querySelectorAll('head script[src]').forEach(function(s){loadedSrcs[s.src]=1});\n var extPromises=[];\n doc.querySelectorAll('head script[src]').forEach(function(s){\n var src=new URL(s.getAttribute('src'),location.origin).href;\n if(loadedSrcs[src])return;\n loadedSrcs[src]=1;\n extPromises.push(new Promise(function(resolve,reject){\n var ns=document.createElement('script');\n ns.src=src;\n ns.onload=resolve;\n ns.onerror=reject;\n document.head.appendChild(ns);\n }));\n });\n\n // ── Script re-execution ──\n // Remove previously injected page scripts\n document.querySelectorAll('script[data-stx-page]').forEach(function(s){s.remove()});\n\n var scripts=[];\n doc.querySelectorAll('script').forEach(function(s){\n var text=s.textContent||'';\n // Skip the signals runtime\n if(text.indexOf('let activeEffect')!==-1)return;\n // Skip the router\n if(text.indexOf('__stxRouter')!==-1)return;\n // Skip layout shell scripts\n if(text.indexOf('__stxDashboardInit')!==-1||text.indexOf('__stxLayoutInit')!==-1)return;\n // Skip external scripts\n if(s.hasAttribute('src'))return;\n // Skip empty\n if(!text.trim())return;\n scripts.push(text);\n });\n\n function execScripts(){\n scripts.forEach(function(text){\n var ns=document.createElement('script');\n ns.textContent=text;\n ns.setAttribute('data-stx-page','');\n document.body.appendChild(ns);\n });\n }\n\n if(extPromises.length>0){\n Promise.all(extPromises).then(execScripts).catch(execScripts);\n }else{\n execScripts();\n }\n\n // Update active nav links\n updateNav(url);\n updateActiveLinks();\n\n // Scroll\n if(o.scrollToTop&&!hash)window.scrollTo({top:0,behavior:'instant'});\n else if(hash){var el=document.querySelector(hash);if(el)el.scrollIntoView({behavior:'smooth'})}\n\n // Update title\n var newTitle=doc.querySelector('title');\n if(newTitle)document.title=newTitle.textContent;\n\n // Push history state\n if(pushState!==false)history.pushState({},'',url+(hash||''));\n\n // Dispatch navigation events\n window.dispatchEvent(new CustomEvent('stx:navigate',{detail:{url:url}}));\n window.dispatchEvent(new Event('stx:load'));\n }\n\n if(o.viewTransitions&&document.startViewTransition){\n document.startViewTransition(doSwap);\n }else{\n // Fallback fade for browsers without View Transitions API\n currentContent.style.transition='opacity 0.12s ease-out';\n currentContent.style.opacity='0';\n setTimeout(function(){\n doSwap();\n currentContent.style.opacity='1';\n setTimeout(function(){currentContent.style.transition=''},150);\n },120);\n }\n }\n\n // ── Link interception ──\n function shouldIntercept(link){\n if(!link)return false;\n var href=link.getAttribute('href');\n if(!href)return false;\n if(href.startsWith('http')||href.startsWith('#')||href.startsWith('mailto:')||href.startsWith('tel:')||href.startsWith('javascript:'))return false;\n if(link.target==='_blank')return false;\n if(link.hasAttribute('data-stx-no-router')||link.hasAttribute('data-no-router')||link.hasAttribute('download'))return false;\n if(href===location.pathname)return false;\n if(!getContainer())return false;\n return true;\n }\n\n document.addEventListener('click',function(e){\n if(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||e.button!==0)return;\n if(!e.target||!e.target.closest)return;\n var link=e.target.closest('a[href]');\n if(!shouldIntercept(link))return;\n e.preventDefault();\n e.stopPropagation();\n navigate(link.getAttribute('href'));\n },true);\n\n // ── Back/forward ──\n window.addEventListener('popstate',function(){\n navigate(location.pathname+location.search+location.hash,false);\n });\n\n // ── Prefetch on hover ──\n if(o.prefetch){\n document.addEventListener('mouseover',function(e){\n if(!e.target||!e.target.closest)return;\n var link=e.target.closest('a[href]');\n if(!shouldIntercept(link))return;\n // Only prefetch links with data-stx-prefetch or all internal links\n var href=link.getAttribute('href');\n if(cache[href]||prefetching[href])return;\n prefetching[href]=true;\n fetch(href,{headers:{'X-STX-Router':'true','Accept':'text/html'}}).then(function(r){return r.text()}).then(function(html){\n if(o.cache)cache[href]=html;\n }).catch(function(){}).finally(function(){delete prefetching[href]});\n },true);\n }\n\n // ── Active link management ──\n function updateNav(url){\n document.querySelectorAll('nav a[href], #mobileNav a[href], [data-stx-nav] a[href]').forEach(function(a){\n var href=a.getAttribute('href');\n if(!href||href.startsWith('#')||href.startsWith('http'))return;\n var isActive=(href===url)||(href==='/'&&url==='/');\n a.style.background=isActive?'var(--nav-active-bg, rgba(0,0,0,0.06))':'';\n a.style.color=isActive?'var(--text-primary, inherit)':'var(--text-nav, inherit)';\n a.style.fontWeight=isActive?'500':'';\n if(a.hasAttribute('data-stx-link')){\n var ac=a.getAttribute('data-stx-active-class')||'active';\n if(isActive)a.classList.add(ac);else a.classList.remove(ac);\n }\n });\n }\n\n function updateActiveLinks(){\n var links=document.querySelectorAll('[data-stx-link]');\n var cur=location.pathname;\n links.forEach(function(link){\n var href=link.getAttribute('href')||'';\n var ac=link.getAttribute('data-stx-active-class')||'active';\n var eac=link.getAttribute('data-stx-exact-active-class')||'exact-active';\n ac.split(' ').forEach(function(cls){if(cls)link.classList.remove(cls)});\n eac.split(' ').forEach(function(cls){if(cls)link.classList.remove(cls)});\n var isExact=cur===href;\n var isActive=href!=='/'?cur.startsWith(href):cur==='/';\n if(isExact)eac.split(' ').forEach(function(cls){if(cls)link.classList.add(cls)});\n if(isActive)ac.split(' ').forEach(function(cls){if(cls)link.classList.add(cls)});\n });\n }\n\n // ── Loading bar + View Transitions CSS ──\n function injectStyles(){\n if(document.getElementById('stx-r-css'))return;\n var s=document.createElement('style');s.id='stx-r-css';\n s.textContent='.stx-navigating{cursor:wait}.stx-navigating *{pointer-events:none}@keyframes stx-l{0%{transform:translateX(-100%)}100%{transform:translateX(100%)}}.stx-navigating::before{content:\\\\'\\\\';position:fixed;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,transparent,#78dce8,transparent);animation:stx-l 1s ease-in-out infinite;z-index:99999}';\n document.head.appendChild(s);\n }\n\n function injectViewTransitionCSS(){\n if(document.getElementById('stx-view-transitions'))return;\n var s=document.createElement('style');s.id='stx-view-transitions';\n s.textContent='::view-transition-group(root){animation:none}::view-transition-old(root){animation:none}::view-transition-new(root){animation:none}#app-content,[data-stx-content]{view-transition-name:stx-content}::view-transition-old(stx-content){animation:stx-fade-out .15s ease-out both}::view-transition-new(stx-content){animation:stx-fade-in .15s ease-in .1s both}@keyframes stx-fade-out{from{opacity:1}to{opacity:0}}@keyframes stx-fade-in{from{opacity:0}to{opacity:1}}::view-transition{background:transparent}::view-transition-group(stx-content){background:inherit;overflow:hidden}';\n (document.head||document.documentElement).appendChild(s);\n }\n\n // ── Public API ──\n var router={\n navigate:navigate,\n navigateTo:navigate,\n prefetch:function(url){\n if(!cache[url]){\n fetch(url,{headers:{'X-STX-Router':'true'}}).then(function(r){return r.text()}).then(function(html){cache[url]=html}).catch(function(){});\n }\n },\n clearCache:function(){for(var k in cache)delete cache[k]},\n cache:cache,\n swap:swap,\n updateNav:updateNav\n };\n\n window.__stxRouter=router;\n window.stxRouter=router;\n if(window.stx)window.stx.router=router;\n\n // ── Initialize ──\n function init(){\n injectStyles();\n injectViewTransitionCSS();\n updateActiveLinks();\n updateNav(location.pathname);\n }\n\n if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',init);else init();\n})();\n`\n}\n"
|
|
12
|
+
],
|
|
13
|
+
"mappings": "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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;",
|
|
14
|
+
"debugId": "3C52557F9211FAA564756E2164756E21",
|
|
15
|
+
"names": []
|
|
16
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function filePathToPattern(filePath: string, pagesDir: string): string;
|
|
2
|
+
export declare function patternToRegex(pattern: string): { regex: RegExp, params: string[] };
|
|
3
|
+
export declare function matchRoute(pathname: string, routes: { pattern: string, regex: RegExp, params: string[] }[]): { route: typeof routes[0], params: Record<string, string> } | null;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AbortNavigationResult, CookieManager, MiddlewareContext, MiddlewareOptions, MiddlewareResult, NavigateToOptions, NavigateToResult, NavigationError, RouteLocation, RouteMiddlewareDefinition, RouteMiddlewareHandler, StorageManager } from './types';
|
|
2
|
+
// =============================================================================
|
|
3
|
+
// Navigation Helpers
|
|
4
|
+
// =============================================================================
|
|
5
|
+
export declare function navigateTo(navPath: string, options?: NavigateToOptions): NavigateToResult;
|
|
6
|
+
export declare function abortNavigation(error: string | NavigationError): AbortNavigationResult;
|
|
7
|
+
// =============================================================================
|
|
8
|
+
// Middleware Definition
|
|
9
|
+
// =============================================================================
|
|
10
|
+
export declare function defineMiddleware(handler: RouteMiddlewareHandler, options?: MiddlewareOptions): RouteMiddlewareDefinition;
|
|
11
|
+
export declare function createServerCookieManager(request: Request, responseHeaders: Headers): CookieManager;
|
|
12
|
+
export declare function createClientCookieManager(): CookieManager;
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Storage Manager
|
|
15
|
+
// =============================================================================
|
|
16
|
+
export declare function createStorageManager(): StorageManager;
|
|
17
|
+
export declare function registerMiddleware(name: string, middleware: RouteMiddlewareDefinition): void;
|
|
18
|
+
export declare function getMiddleware(name: string): RouteMiddlewareDefinition | undefined;
|
|
19
|
+
export declare function hasMiddleware(name: string): boolean;
|
|
20
|
+
export declare function clearMiddleware(): void;
|
|
21
|
+
export declare function getMiddlewareNames(): string[];
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// Middleware Loading
|
|
24
|
+
// =============================================================================
|
|
25
|
+
export declare function loadMiddlewareFromDirectory(baseDir: string, middlewareDir?: string): Promise<void>;
|
|
26
|
+
export declare function createRouteLocation(pathname: string, params: Record<string, string>, meta: Record<string, unknown>, search?: string): RouteLocation;
|
|
27
|
+
export declare function createMiddlewareContext(to: RouteLocation, from: RouteLocation | null, request?: Request): MiddlewareContext;
|
|
28
|
+
export declare function runMiddleware(middlewareNames: string | string[], context: MiddlewareContext): Promise<MiddlewareResult>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function setAppUrl(url: string): void;
|
|
2
|
+
export declare function defineRoute(name: string, routePath: string, params?: Record<string, any>): void;
|
|
3
|
+
export declare function defineRoutes(routeDefinitions: Record<string, string | RouteDefinition>): void;
|
|
4
|
+
export declare function route(name: string, params?: Record<string, any>, absolute?: boolean): string;
|
|
5
|
+
export declare function resetRoutes(): void;
|
|
6
|
+
declare interface RouteDefinition {
|
|
7
|
+
path: string
|
|
8
|
+
name?: string
|
|
9
|
+
params?: Record<string, any>
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveLayoutChain(routeFilePath: string, pagesDir: string): string[];
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export declare interface Route {
|
|
2
|
+
pattern: string
|
|
3
|
+
regex: RegExp
|
|
4
|
+
params: string[]
|
|
5
|
+
filePath: string
|
|
6
|
+
isDynamic: boolean
|
|
7
|
+
layout?: string
|
|
8
|
+
middleware?: string[]
|
|
9
|
+
meta?: Record<string, unknown>
|
|
10
|
+
}
|
|
11
|
+
export declare interface RouteMatch {
|
|
12
|
+
route: Route
|
|
13
|
+
params: Record<string, string>
|
|
14
|
+
}
|
|
15
|
+
export declare interface RouterConfig {
|
|
16
|
+
pagesDir?: string
|
|
17
|
+
extensions?: string[]
|
|
18
|
+
layouts?: boolean
|
|
19
|
+
middleware?: boolean
|
|
20
|
+
trailingSlash?: boolean
|
|
21
|
+
caseSensitive?: boolean
|
|
22
|
+
}
|
|
23
|
+
export declare interface RouteLocation {
|
|
24
|
+
path: string
|
|
25
|
+
params: Record<string, string>
|
|
26
|
+
query: Record<string, string>
|
|
27
|
+
fullPath: string
|
|
28
|
+
meta: Record<string, unknown>
|
|
29
|
+
}
|
|
30
|
+
export declare interface CookieOptions {
|
|
31
|
+
expires?: Date | number
|
|
32
|
+
path?: string
|
|
33
|
+
domain?: string
|
|
34
|
+
secure?: boolean
|
|
35
|
+
httpOnly?: boolean
|
|
36
|
+
sameSite?: 'strict' | 'lax' | 'none'
|
|
37
|
+
}
|
|
38
|
+
export declare interface CookieManager {
|
|
39
|
+
get(name: string): string | undefined
|
|
40
|
+
set(name: string, value: string, options?: CookieOptions): void
|
|
41
|
+
delete(name: string): void
|
|
42
|
+
getAll(): Record<string, string>
|
|
43
|
+
}
|
|
44
|
+
export declare interface StorageManager {
|
|
45
|
+
get(key: string): string | null
|
|
46
|
+
set(key: string, value: string): void
|
|
47
|
+
remove(key: string): void
|
|
48
|
+
isAvailable(): boolean
|
|
49
|
+
}
|
|
50
|
+
export declare interface MiddlewareContext {
|
|
51
|
+
to: RouteLocation
|
|
52
|
+
from: RouteLocation | null
|
|
53
|
+
isClient: boolean
|
|
54
|
+
isServer: boolean
|
|
55
|
+
cookies: CookieManager
|
|
56
|
+
storage: StorageManager
|
|
57
|
+
state: Record<string, unknown>
|
|
58
|
+
request?: Request
|
|
59
|
+
responseHeaders: Headers
|
|
60
|
+
}
|
|
61
|
+
export declare interface MiddlewareOptions {
|
|
62
|
+
mode?: MiddlewareMode
|
|
63
|
+
}
|
|
64
|
+
export declare interface RouteMiddlewareDefinition {
|
|
65
|
+
handler: RouteMiddlewareHandler
|
|
66
|
+
mode: MiddlewareMode
|
|
67
|
+
}
|
|
68
|
+
export declare interface NavigateToOptions {
|
|
69
|
+
replace?: boolean
|
|
70
|
+
external?: boolean
|
|
71
|
+
redirectCode?: 301 | 302 | 303 | 307 | 308
|
|
72
|
+
}
|
|
73
|
+
export declare interface NavigateToResult {
|
|
74
|
+
type: 'redirect'
|
|
75
|
+
path: string
|
|
76
|
+
options: NavigateToOptions
|
|
77
|
+
}
|
|
78
|
+
export declare interface NavigationError {
|
|
79
|
+
statusCode: number
|
|
80
|
+
message: string
|
|
81
|
+
}
|
|
82
|
+
export declare interface AbortNavigationResult {
|
|
83
|
+
type: 'abort'
|
|
84
|
+
error: NavigationError
|
|
85
|
+
}
|
|
86
|
+
export declare interface MiddlewareResult {
|
|
87
|
+
passed: boolean
|
|
88
|
+
redirect?: NavigateToResult
|
|
89
|
+
abort?: AbortNavigationResult
|
|
90
|
+
state: Record<string, unknown>
|
|
91
|
+
responseHeaders: Headers
|
|
92
|
+
}
|
|
93
|
+
export type MiddlewareMode = 'universal' | 'server' | 'client';
|
|
94
|
+
export type RouteMiddlewareHandler = (
|
|
95
|
+
context: MiddlewareContext,
|
|
96
|
+
) => void | Promise<void> | NavigationResult | Promise<NavigationResult | void>;
|
|
97
|
+
export type NavigationResult = NavigateToResult | AbortNavigationResult;
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stx-router",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.2.8",
|
|
5
|
+
"description": "File-based router for STX — .stx template discovery, nested layouts, typed route params, middleware, and client-side SPA navigation.",
|
|
6
|
+
"author": "Chris Breuer <chris@stacksjs.org>",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/stacksjs/stx#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/stacksjs/stx.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/stacksjs/stx/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"router",
|
|
18
|
+
"file-based",
|
|
19
|
+
"middleware",
|
|
20
|
+
"typed-routes",
|
|
21
|
+
"nested-layouts",
|
|
22
|
+
"spa",
|
|
23
|
+
"bun",
|
|
24
|
+
"stx"
|
|
25
|
+
],
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./*": {
|
|
32
|
+
"import": "./dist/*"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"module": "./dist/index.js",
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"files": [
|
|
38
|
+
"LICENSE.md",
|
|
39
|
+
"README.md",
|
|
40
|
+
"dist"
|
|
41
|
+
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "bun --bun build.ts",
|
|
44
|
+
"prepublishOnly": "bun run build",
|
|
45
|
+
"test": "bun test",
|
|
46
|
+
"test:watch": "bun test --watch",
|
|
47
|
+
"test:coverage": "bun test --coverage",
|
|
48
|
+
"typecheck": "bun tsc --noEmit"
|
|
49
|
+
}
|
|
50
|
+
}
|