@teamvelix/velix 5.2.1 → 5.2.3

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../build/index.ts","../../config.ts","../../router/index.ts","../../utils.ts","../../version.ts","../../logger.ts","../../runtime/start-build.ts"],"sourcesContent":["/**\n * Velix v5 Build System\n * Production build using esbuild\n */\n\nimport esbuild from 'esbuild';\nimport fs from 'fs';\nimport path from 'path';\nimport { loadConfig, resolvePaths } from '../config.js';\nimport { buildRouteTree } from '../router/index.js';\nimport { ensureDir, cleanDir, findFiles, formatBytes, formatTime } from '../utils.js';\nimport logger from '../logger.js';\nimport { VERSION } from '../version.js';\n\nexport interface BuildOptions {\n projectRoot?: string;\n outDir?: string;\n minify?: boolean;\n sourcemap?: boolean;\n}\n\n/**\n * Build the Velix application for production\n */\nexport async function build(options: BuildOptions = {}) {\n const projectRoot = options.projectRoot || process.cwd();\n const config = await loadConfig(projectRoot);\n const resolved = resolvePaths(config, projectRoot);\n\n const outDir = options.outDir || resolved.resolvedOutDir;\n const startTime = Date.now();\n\n logger.logo();\n logger.info('Building for production...');\n logger.blank();\n\n // Clean output directory\n cleanDir(outDir);\n\n const appDir = resolved.resolvedAppDir;\n const routes = buildRouteTree(appDir);\n\n // Collect all source files\n const sourceFiles = findFiles(appDir, /\\.(tsx?|jsx?)$/);\n\n if (sourceFiles.length === 0) {\n logger.warn('No source files found in app/ directory');\n return;\n }\n\n // Build server bundle\n try {\n const serverOutDir = path.join(outDir, 'server');\n ensureDir(serverOutDir);\n\n await esbuild.build({\n entryPoints: sourceFiles,\n outdir: serverOutDir,\n bundle: false,\n format: 'esm',\n platform: 'node',\n target: config.build.target,\n minify: options.minify ?? config.build.minify,\n sourcemap: options.sourcemap ?? config.build.sourcemap,\n jsx: 'automatic',\n logLevel: 'silent',\n treeShaking: true,\n legalComments: 'none',\n });\n\n logger.success('Server bundle built');\n } catch (err: any) {\n logger.error('Server build failed', err);\n process.exit(1);\n }\n\n // Build client bundle (client components and islands)\n try {\n const clientOutDir = path.join(outDir, 'client');\n ensureDir(clientOutDir);\n\n const clientFiles = sourceFiles.filter(f => {\n const content = fs.readFileSync(f, 'utf-8');\n const firstLine = content.split('\\n')[0]?.trim();\n return firstLine === \"'use client'\" || firstLine === '\"use client\"' ||\n firstLine === \"'use island'\" || firstLine === '\"use island\"';\n });\n\n if (clientFiles.length > 0) {\n await esbuild.build({\n entryPoints: clientFiles,\n outdir: clientOutDir,\n bundle: true,\n format: 'esm',\n platform: 'browser',\n target: ['es2022'],\n minify: options.minify ?? config.build.minify,\n sourcemap: options.sourcemap ?? config.build.sourcemap,\n splitting: config.build.splitting,\n jsx: 'automatic',\n logLevel: 'silent',\n external: ['react', 'react-dom'],\n treeShaking: true,\n legalComments: 'none',\n drop: options.minify ?? config.build.minify ? ['console', 'debugger'] : [],\n chunkNames: 'chunks/[name]-[hash]',\n });\n\n logger.success(`Client bundle built (${clientFiles.length} components)`);\n }\n } catch (err: any) {\n logger.error('Client build failed', err);\n process.exit(1);\n }\n\n // Copy public directory\n const publicDir = resolved.resolvedPublicDir;\n if (fs.existsSync(publicDir)) {\n const publicOutDir = path.join(outDir, 'public');\n ensureDir(publicOutDir);\n copyDirRecursive(publicDir, publicOutDir);\n logger.success('Static assets copied');\n }\n\n // Generate build manifest\n const manifest = {\n version: VERSION,\n buildTime: new Date().toISOString(),\n routes: routes.appRoutes.map(r => ({\n path: r.path,\n type: r.path.includes(':') ? 'dynamic' : 'static',\n })),\n api: routes.api.map(r => ({ path: r.path })),\n };\n\n fs.writeFileSync(path.join(outDir, 'manifest.json'), JSON.stringify(manifest, null, 2));\n\n const elapsed = Date.now() - startTime;\n const totalSize = getDirSize(outDir);\n\n logger.blank();\n logger.divider();\n logger.blank();\n\n // Log routes\n routes.appRoutes.forEach(r => {\n const type = r.path.includes(':') || r.path.includes('*') ? 'dynamic' : 'static';\n logger.route(r.path, type);\n });\n routes.api.forEach(r => logger.route(r.path, 'api'));\n\n logger.blank();\n logger.build({ time: elapsed });\n logger.info(`Output: ${outDir} (${formatBytes(totalSize)})`);\n logger.blank();\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction copyDirRecursive(src: string, dest: string) {\n ensureDir(dest);\n const entries = fs.readdirSync(src, { withFileTypes: true });\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) copyDirRecursive(srcPath, destPath);\n else fs.copyFileSync(srcPath, destPath);\n }\n}\n\nfunction getDirSize(dir: string): number {\n let size = 0;\n if (!fs.existsSync(dir)) return size;\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) size += getDirSize(fullPath);\n else size += fs.statSync(fullPath).size;\n }\n return size;\n}\n\nexport default { build };\n","/**\n * Velix v5 Configuration System\n * Handles loading, validation, and merging of velix.config.ts\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport { pathToFileURL } from 'url';\nimport { z } from 'zod';\nimport pc from 'picocolors';\n\n// ============================================================================\n// Configuration Schema (Zod validation)\n// ============================================================================\n\nconst AppConfigSchema = z.object({\n name: z.string().default('Velix App'),\n url: z.string().url().optional(),\n}).default({});\n\nconst ServerConfigSchema = z.object({\n port: z.number().min(1).max(65535).default(3000),\n host: z.string().default('localhost'),\n}).default({});\n\nconst RoutingConfigSchema = z.object({\n trailingSlash: z.boolean().default(false),\n}).default({});\n\nconst SEOConfigSchema = z.object({\n sitemap: z.boolean().default(true),\n robots: z.boolean().default(true),\n openGraph: z.boolean().default(true),\n}).default({});\n\nconst BuildConfigSchema = z.object({\n target: z.string().default('es2022'),\n minify: z.boolean().default(true),\n sourcemap: z.boolean().default(true),\n splitting: z.boolean().default(true),\n outDir: z.string().default('.velix'),\n}).default({});\n\nconst ExperimentalConfigSchema = z.object({\n islands: z.boolean().default(true),\n streaming: z.boolean().default(true),\n}).default({});\n\nconst PluginSchema = z.union([\n z.string(),\n z.object({\n name: z.string()\n }).passthrough(),\n]);\n\nexport const VelixConfigSchema = z.object({\n // App identity\n app: AppConfigSchema,\n\n // DevTools toggle\n devtools: z.boolean().default(true),\n\n // Server options\n server: ServerConfigSchema,\n\n // Routing options\n routing: RoutingConfigSchema,\n\n // SEO configuration\n seo: SEOConfigSchema,\n\n // Build options\n build: BuildConfigSchema,\n\n // Experimental features\n experimental: ExperimentalConfigSchema,\n\n // Plugins\n plugins: z.array(PluginSchema).default([]),\n\n // Directories (resolved automatically)\n appDir: z.string().default('app'),\n publicDir: z.string().default('public'),\n\n // Stylesheets\n styles: z.array(z.string()).default([]),\n\n // Favicon\n favicon: z.string().nullable().default(null),\n});\n\nexport type VelixConfig = z.infer<typeof VelixConfigSchema>;\n\n// ============================================================================\n// Default configuration\n// ============================================================================\n\nexport const defaultConfig: VelixConfig = VelixConfigSchema.parse({});\n\n// ============================================================================\n// defineConfig helper\n// ============================================================================\n\n/**\n * Helper function to define configuration with full type support.\n * Use this in your velix.config.ts file.\n *\n * @example\n * ```ts\n * import { defineConfig } from \"velix\";\n *\n * export default defineConfig({\n * app: { name: \"My App\" },\n * server: { port: 3000 },\n * seo: { sitemap: true }\n * });\n * ```\n */\nexport function defineConfig(config: Partial<VelixConfig>): Partial<VelixConfig> {\n return config;\n}\n\n// ============================================================================\n// Config Loader\n// ============================================================================\n\n/**\n * Loads and validates configuration from velix.config.ts\n */\nexport async function loadConfig(projectRoot: string): Promise<VelixConfig> {\n const configPathTs = path.join(projectRoot, 'velix.config.ts');\n const configPathJs = path.join(projectRoot, 'velix.config.js');\n // Support legacy config for migration\n const configPathLegacyTs = path.join(projectRoot, 'flexireact.config.ts');\n const configPathLegacyJs = path.join(projectRoot, 'flexireact.config.js');\n\n let configPath: string | null = null;\n if (fs.existsSync(configPathTs)) configPath = configPathTs;\n else if (fs.existsSync(configPathJs)) configPath = configPathJs;\n else if (fs.existsSync(configPathLegacyTs)) configPath = configPathLegacyTs;\n else if (fs.existsSync(configPathLegacyJs)) configPath = configPathLegacyJs;\n\n let userConfig: Partial<VelixConfig> = {};\n\n if (configPath) {\n try {\n const configUrl = pathToFileURL(configPath).href;\n const module = await import(`${configUrl}?t=${Date.now()}`);\n userConfig = module.default || module;\n } catch (error: any) {\n console.warn(pc.yellow(`⚠ Failed to load config: ${error.message}`));\n }\n }\n\n // Merge and validate with Zod\n const merged = deepMerge(defaultConfig, userConfig as Record<string, any>);\n\n try {\n return VelixConfigSchema.parse(merged);\n } catch (err: unknown) {\n if (err instanceof z.ZodError) {\n console.error(pc.red('✖ Configuration validation failed:'));\n for (const issue of err.issues) {\n console.error(pc.dim(` - ${issue.path.join('.')}: ${issue.message}`));\n }\n process.exit(1);\n }\n throw err;\n }\n}\n\n// ============================================================================\n// Path Resolution\n// ============================================================================\n\n/**\n * Resolves all paths in config relative to project root\n */\nexport function resolvePaths(config: VelixConfig, projectRoot: string): VelixConfig & { resolvedAppDir: string; resolvedPublicDir: string; resolvedOutDir: string } {\n return {\n ...config,\n resolvedAppDir: path.resolve(projectRoot, config.appDir),\n resolvedPublicDir: path.resolve(projectRoot, config.publicDir),\n resolvedOutDir: path.resolve(projectRoot, config.build.outDir),\n };\n}\n\n// ============================================================================\n// Utility: Deep merge\n// ============================================================================\n\nfunction deepMerge(target: Record<string, any>, source: Record<string, any>): Record<string, any> {\n const result = { ...target };\n\n for (const key in source) {\n if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {\n result[key] = deepMerge(target[key] || {}, source[key]);\n } else {\n result[key] = source[key];\n }\n }\n\n return result;\n}\n","/**\n * Velix v5 Router\n * File-based routing using the app/ directory convention\n *\n * Supports:\n * - app/page.tsx → /\n * - app/dashboard/page.tsx → /dashboard\n * - app/blog/[slug]/page.tsx → /blog/:slug\n * - app/(group)/page.tsx → / (route groups)\n * - app/[...slug]/page.tsx → catch-all routes\n * - layout.tsx, loading.tsx, error.tsx, not-found.tsx\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport { isServerComponent, isClientComponent, isIsland } from '../utils.js';\nimport type { Route, RouteTree as TypedRouteTree, RouteTreeNode } from '../types.js';\n\n// ============================================================================\n// Route Types\n// ============================================================================\n\nexport const RouteType = {\n PAGE: 'page',\n API: 'api',\n LAYOUT: 'layout',\n LOADING: 'loading',\n ERROR: 'error',\n NOT_FOUND: 'not-found'\n} as const;\n\n// ============================================================================\n// Build Route Tree\n// ============================================================================\n\n/**\n * Builds the complete route tree from the app/ directory\n */\nexport function buildRouteTree(appDir: string) {\n const projectRoot = path.dirname(appDir);\n\n const routes: {\n pages: Route[];\n api: Route[];\n layouts: Map<string, string>;\n tree: RouteTreeNode;\n appRoutes: Route[];\n rootLayout?: string;\n } = {\n pages: [],\n api: [],\n layouts: new Map(),\n tree: { children: {}, routes: [] },\n appRoutes: [],\n };\n\n // Scan app/ directory\n if (fs.existsSync(appDir)) {\n scanAppDirectory(appDir, appDir, routes);\n }\n\n // Scan server/api/ for API routes\n const serverApiDir = path.join(projectRoot, 'server', 'api');\n if (fs.existsSync(serverApiDir)) {\n scanApiDirectory(serverApiDir, serverApiDir, routes);\n }\n\n // Check for root layout\n const rootLayoutTsx = path.join(appDir, 'layout.tsx');\n const rootLayoutJsx = path.join(appDir, 'layout.jsx');\n if (fs.existsSync(rootLayoutTsx)) routes.rootLayout = rootLayoutTsx;\n else if (fs.existsSync(rootLayoutJsx)) routes.rootLayout = rootLayoutJsx;\n\n // Build route tree for nested routes\n routes.tree = buildTree(routes.appRoutes);\n\n return routes;\n}\n\n// ============================================================================\n// App Directory Scanner\n// ============================================================================\n\n/**\n * Scans app/ directory for file-based routing\n * Supports: page.tsx, layout.tsx, loading.tsx, error.tsx, not-found.tsx, [param].tsx\n */\nfunction scanAppDirectory(\n baseDir: string,\n currentDir: string,\n routes: { appRoutes: Route[] },\n parentSegments: string[] = [],\n parentLayout: string | null = null,\n parentMiddleware: string | null = null\n) {\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\n\n // Find special files in current directory\n const specialFiles: Record<string, string | null> = {\n page: null,\n layout: null,\n loading: null,\n error: null,\n notFound: null,\n template: null,\n middleware: null\n };\n\n for (const entry of entries) {\n if (entry.isFile()) {\n const name = entry.name.replace(/\\.(jsx|js|tsx|ts)$/, '');\n const fullPath = path.join(currentDir, entry.name);\n const ext = path.extname(entry.name);\n\n // Only process relevant extensions\n if (!['.tsx', '.jsx', '.ts', '.js'].includes(ext)) continue;\n\n if (name === 'page') specialFiles.page = fullPath;\n if (name === 'layout') specialFiles.layout = fullPath;\n if (name === 'loading') specialFiles.loading = fullPath;\n if (name === 'error') specialFiles.error = fullPath;\n if (name === 'not-found') specialFiles.notFound = fullPath;\n if (name === 'template') specialFiles.template = fullPath;\n if (name === 'middleware' || name === '_middleware') specialFiles.middleware = fullPath;\n\n // Handle [param].tsx files directly in app/ (alternative to [param]/page.tsx)\n if (name.startsWith('[') && name.endsWith(']') && ['.tsx', '.jsx'].includes(ext)) {\n const paramName = name.slice(1, -1);\n let segmentName: string;\n\n if (paramName.startsWith('...')) {\n segmentName = '*' + paramName.slice(3);\n } else {\n segmentName = ':' + paramName;\n }\n\n const routePath = '/' + [...parentSegments, segmentName].join('/');\n\n routes.appRoutes.push({\n type: RouteType.PAGE,\n path: routePath.replace(/\\/+/g, '/'),\n filePath: fullPath,\n pattern: createRoutePattern(routePath),\n segments: [...parentSegments, segmentName],\n layout: specialFiles.layout || parentLayout,\n loading: specialFiles.loading,\n error: specialFiles.error,\n notFound: specialFiles.notFound,\n template: specialFiles.template,\n middleware: specialFiles.middleware || parentMiddleware,\n isServerComponent: isServerComponent(fullPath),\n isClientComponent: isClientComponent(fullPath),\n isIsland: isIsland(fullPath),\n });\n }\n }\n }\n\n // If there's a page.tsx, create a route for this directory\n if (specialFiles.page) {\n const routePath = '/' + parentSegments.join('/') || '/';\n\n routes.appRoutes.push({\n type: RouteType.PAGE,\n path: routePath.replace(/\\/+/g, '/') || '/',\n filePath: specialFiles.page,\n pattern: createRoutePattern(routePath || '/'),\n segments: parentSegments,\n layout: specialFiles.layout || parentLayout,\n loading: specialFiles.loading,\n error: specialFiles.error,\n notFound: specialFiles.notFound,\n template: specialFiles.template,\n middleware: specialFiles.middleware || parentMiddleware,\n isServerComponent: isServerComponent(specialFiles.page),\n isClientComponent: isClientComponent(specialFiles.page),\n isIsland: isIsland(specialFiles.page),\n });\n }\n\n // Recursively scan subdirectories\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const fullPath = path.join(currentDir, entry.name);\n\n // Skip special directories\n if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue;\n\n // Handle route groups (parentheses) — don't add to URL\n const isGroup = entry.name.startsWith('(') && entry.name.endsWith(')');\n\n // Handle dynamic segments [param]\n let segmentName = entry.name;\n if (entry.name.startsWith('[') && entry.name.endsWith(']')) {\n segmentName = ':' + entry.name.slice(1, -1);\n if (entry.name.startsWith('[...')) {\n segmentName = '*' + entry.name.slice(4, -1);\n }\n if (entry.name.startsWith('[[...')) {\n segmentName = '*' + entry.name.slice(5, -2);\n }\n }\n\n const newSegments = isGroup ? parentSegments : [...parentSegments, segmentName];\n const newLayout = specialFiles.layout || parentLayout;\n const newMiddleware = specialFiles.middleware || parentMiddleware;\n\n scanAppDirectory(baseDir, fullPath, routes, newSegments, newLayout, newMiddleware);\n }\n }\n}\n\n// ============================================================================\n// API Directory Scanner (server/api/)\n// ============================================================================\n\nfunction scanApiDirectory(baseDir: string, currentDir: string, routes: { api: Route[] }, parentSegments: string[] = []) {\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n\n if (entry.isDirectory()) {\n scanApiDirectory(baseDir, fullPath, routes, [...parentSegments, entry.name]);\n } else if (entry.isFile()) {\n const ext = path.extname(entry.name);\n if (!['.ts', '.js'].includes(ext)) continue;\n\n const baseName = path.basename(entry.name, ext);\n // route.ts maps to the parent path, other names become segments\n const apiSegments = baseName === 'route' || baseName === 'index'\n ? parentSegments\n : [...parentSegments, baseName];\n\n const apiPath = '/api/' + apiSegments.join('/');\n\n routes.api.push({\n type: RouteType.API,\n path: apiPath.replace(/\\/+/g, '/') || '/api',\n filePath: fullPath,\n pattern: createRoutePattern(apiPath),\n segments: ['api', ...apiSegments].filter(Boolean),\n });\n }\n }\n}\n\n// ============================================================================\n// Route Matching\n// ============================================================================\n\n/**\n * Creates regex pattern for route matching\n */\nfunction createRoutePattern(routePath: string): RegExp {\n let pattern = routePath\n .replace(/\\*[^/]*/g, '(.*)') // Catch-all\n .replace(/:[^/]+/g, '([^/]+)') // Dynamic segments\n .replace(/\\//g, '\\\\/');\n\n return new RegExp(`^${pattern}$`);\n}\n\n/**\n * Matches URL path against routes\n */\nexport function matchRoute(urlPath: string, routes: Route[]) {\n const normalizedPath = urlPath === '' ? '/' : urlPath.split('?')[0];\n\n for (const route of routes) {\n const match = normalizedPath.match(route.pattern);\n if (match) {\n const params = extractParams(route.path, match);\n return { ...route, params };\n }\n }\n\n return null;\n}\n\n/**\n * Extracts parameters from route match\n */\nfunction extractParams(routePath: string, match: RegExpMatchArray): Record<string, string> {\n const params: Record<string, string> = {};\n const paramNames: string[] = [];\n\n const paramRegex = /:([^/]+)|\\*([^/]*)/g;\n let paramMatch;\n while ((paramMatch = paramRegex.exec(routePath)) !== null) {\n paramNames.push(paramMatch[1] || paramMatch[2] || 'splat');\n }\n\n paramNames.forEach((name, index) => {\n params[name] = match[index + 1];\n });\n\n return params;\n}\n\n// ============================================================================\n// Layout Resolution\n// ============================================================================\n\n/**\n * Finds all layouts that apply to a route\n */\nexport function findRouteLayouts(route: Route, layoutsMap: Map<string, string>): Array<{ name: string; filePath: string | undefined }> {\n const layouts: Array<{ name: string; filePath: string | undefined }> = [];\n\n // Check for segment-based layouts\n for (const segment of route.segments) {\n if (layoutsMap.has(segment)) {\n layouts.push({ name: segment, filePath: layoutsMap.get(segment) });\n }\n }\n\n // Check for route-specific layout\n if (route.layout) {\n layouts.push({ name: 'route', filePath: route.layout });\n }\n\n // Check for root layout\n if (layoutsMap.has('root')) {\n layouts.unshift({ name: 'root', filePath: layoutsMap.get('root') });\n }\n\n return layouts;\n}\n\n// ============================================================================\n// Tree Building\n// ============================================================================\n\nfunction buildTree(routes: Route[]): RouteTreeNode {\n const tree: RouteTreeNode = { children: {}, routes: [] };\n\n for (const route of routes) {\n let current = tree;\n for (const segment of route.segments) {\n if (!current.children[segment]) {\n current.children[segment] = { children: {}, routes: [] };\n }\n current = current.children[segment];\n }\n current.routes.push(route);\n }\n\n return tree;\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n buildRouteTree,\n matchRoute,\n findRouteLayouts,\n RouteType\n};\n","/**\n * Velix v5 Utility Functions\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport crypto from 'crypto';\n\n/**\n * Generates a unique hash for cache busting\n */\nexport function generateHash(content: string): string {\n return crypto.createHash('md5').update(content).digest('hex').slice(0, 8);\n}\n\n/**\n * Escapes HTML special characters\n */\nexport function escapeHtml(str: string): string {\n const htmlEntities: Record<string, string> = {\n '&': '&amp;', '<': '&lt;', '>': '&gt;',\n '\"': '&quot;', \"'\": '&#39;'\n };\n return String(str).replace(/[&<>\"']/g, char => htmlEntities[char]);\n}\n\n/**\n * Recursively finds all files matching a pattern\n */\nexport function findFiles(dir: string, pattern: RegExp, files: string[] = []): string[] {\n if (!fs.existsSync(dir)) return files;\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) findFiles(fullPath, pattern, files);\n else if (pattern.test(entry.name)) files.push(fullPath);\n }\n return files;\n}\n\n/**\n * Ensures a directory exists\n */\nexport function ensureDir(dir: string): void {\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n}\n\n/**\n * Cleans a directory\n */\nexport function cleanDir(dir: string): void {\n if (fs.existsSync(dir)) fs.rmSync(dir, { recursive: true, force: true });\n fs.mkdirSync(dir, { recursive: true });\n}\n\n/**\n * Copies a directory recursively\n */\nexport function copyDir(src: string, dest: string): void {\n ensureDir(dest);\n const entries = fs.readdirSync(src, { withFileTypes: true });\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) copyDir(srcPath, destPath);\n else fs.copyFileSync(srcPath, destPath);\n }\n}\n\n/**\n * Debounce function for file watching\n */\nexport function debounce<T extends (...args: unknown[]) => unknown>(fn: T, delay: number): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n return (...args: Parameters<T>) => {\n clearTimeout(timeout);\n timeout = setTimeout(() => fn(...args), delay);\n };\n}\n\n/**\n * Formats bytes to human-readable string\n */\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n}\n\n/**\n * Formats milliseconds to human-readable string\n */\nexport function formatTime(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n return `${(ms / 1000).toFixed(2)}s`;\n}\n\n/**\n * Creates a deferred promise\n */\nexport function createDeferred<T>() {\n let resolve: (value: T | PromiseLike<T>) => void;\n let reject: (reason?: unknown) => void;\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n return { promise, resolve: resolve!, reject: reject! };\n}\n\n/**\n * Sleep utility\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Check if a file is a server component (has 'use server' directive)\n */\nexport function isServerComponent(filePath: string): boolean {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const firstLine = content.split('\\n')[0].trim();\n return firstLine === \"'use server'\" || firstLine === '\"use server\"';\n } catch { return false; }\n}\n\n/**\n * Check if a file is a client component (has 'use client' directive)\n */\nexport function isClientComponent(filePath: string): boolean {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const firstLine = content.split('\\n')[0].trim();\n return firstLine === \"'use client'\" || firstLine === '\"use client\"';\n } catch { return false; }\n}\n\n/**\n * Check if a component is an island (has 'use island' directive)\n */\nexport function isIsland(filePath: string): boolean {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const firstLine = content.split('\\n')[0].trim();\n return firstLine === \"'use island'\" || firstLine === '\"use island\"';\n } catch { return false; }\n}\n","/**\n * Velix version — single source of truth.\n * Update this file only when releasing a new version.\n */\nexport const VERSION = '5.1.7';\n","/**\n * Velix v5 Logger\n * Minimalist, professional output inspired by modern CLIs\n */\n\nimport { VERSION } from './version.js';\n\nconst colors = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n magenta: '\\x1b[35m',\n cyan: '\\x1b[36m',\n white: '\\x1b[37m',\n gray: '\\x1b[90m',\n};\n\nconst c = colors;\n\nfunction getTime() {\n const now = new Date();\n const hours = String(now.getHours()).padStart(2, '0');\n const minutes = String(now.getMinutes()).padStart(2, '0');\n const seconds = String(now.getSeconds()).padStart(2, '0');\n return `${c.dim}${hours}:${minutes}:${seconds}${c.reset}`;\n}\n\nfunction getStatusColor(status: number) {\n if (status >= 500) return c.red;\n if (status >= 400) return c.yellow;\n if (status >= 300) return c.cyan;\n if (status >= 200) return c.green;\n return c.white;\n}\n\nfunction fmtTime(ms: number) {\n if (ms < 1) return `${c.gray}<1ms${c.reset}`;\n if (ms < 100) return `${c.green}${ms}ms${c.reset}`;\n if (ms < 500) return `${c.yellow}${ms}ms${c.reset}`;\n return `${c.red}${ms}ms${c.reset}`;\n}\n\nconst LOGO = `\n ${c.cyan}▲${c.reset} ${c.bold}Velix${c.reset} ${c.dim}v${VERSION}${c.reset}\n`;\n\nexport const logger = {\n logo() {\n console.log(LOGO);\n console.log(`${c.dim} ──────────────────────────────────────────────${c.reset}`);\n console.log('');\n },\n\n serverStart(config: { port: number | string; host: string; mode: string; pagesDir?: string }, startTime = Date.now()) {\n const { port, host, mode, pagesDir } = config;\n const elapsed = Date.now() - startTime;\n\n console.log(LOGO);\n console.log(` ${c.green}✔${c.reset} ${c.bold}Ready${c.reset} in ${elapsed}ms`);\n console.log('');\n console.log(` ${c.bold}Local:${c.reset} ${c.cyan}http://${host}:${port}${c.reset}`);\n console.log(` ${c.bold}Mode:${c.reset} ${mode === 'development' ? c.yellow : c.green}${mode}${c.reset}`);\n if (pagesDir) console.log(` ${c.bold}App:${c.reset} ${c.dim}${pagesDir}${c.reset}`);\n console.log('');\n },\n\n request(method: string, path: string, status: number, time: number, extra: { type?: string } = {}) {\n const statusColor = getStatusColor(status);\n const timeStr = fmtTime(time);\n\n let badge = `${c.dim}○${c.reset}`;\n if (extra.type === 'dynamic' || extra.type === 'ssr') badge = `${c.white}ƒ${c.reset}`;\n else if (extra.type === 'api') badge = `${c.cyan}λ${c.reset}`;\n\n const statusStr = `${statusColor}${status}${c.reset}`;\n console.log(` ${badge} ${c.white}${method}${c.reset} ${path} ${statusStr} ${c.dim}${timeStr}${c.reset}`);\n },\n\n info(msg: string) { console.log(` ${c.cyan}ℹ${c.reset} ${msg}`); },\n success(msg: string) { console.log(` ${c.green}✔${c.reset} ${msg}`); },\n warn(msg: string) { console.log(` ${c.yellow}⚠${c.reset} ${c.yellow}${msg}${c.reset}`); },\n\n error(msg: string, err: Error | null = null) {\n console.log(` ${c.red}✖${c.reset} ${c.red}${msg}${c.reset}`);\n if (err?.stack) {\n console.log('');\n console.log(`${c.dim}${err.stack.split('\\n').slice(1, 4).join('\\n')}${c.reset}`);\n console.log('');\n }\n },\n\n compile(file: string, time: number) {\n console.log(` ${c.white}●${c.reset} Compiling ${c.dim}${file}${c.reset} ${c.dim}(${time}ms)${c.reset}`);\n },\n\n hmr(file: string) {\n console.log(` ${c.green}↻${c.reset} Fast Refresh ${c.dim}${file}${c.reset}`);\n },\n\n plugin(name: string) {\n console.log(` ${c.cyan}◆${c.reset} Plugin ${c.dim}${name}${c.reset}`);\n },\n\n route(path: string, type: string) {\n const typeLabel = type === 'api' ? 'λ' : type === 'dynamic' ? 'ƒ' : '○';\n const color = type === 'api' ? c.cyan : type === 'dynamic' ? c.white : c.dim;\n console.log(` ${color}${typeLabel}${c.reset} ${path}`);\n },\n\n divider() { console.log(`${c.dim} ──────────────────────────────────────────────${c.reset}`); },\n blank() { console.log(''); },\n\n portInUse(port: number | string) {\n this.error(`Port ${port} is already in use.`);\n this.blank();\n console.log(` ${c.dim}Try:${c.reset}`);\n console.log(` 1. Kill the process on port ${port}`);\n console.log(` 2. Use a different port via PORT env var`);\n this.blank();\n },\n\n build(stats: { time: number }) {\n this.blank();\n console.log(` ${c.green}✔${c.reset} Build completed`);\n this.blank();\n console.log(` ${c.dim}Total time:${c.reset} ${c.white}${stats.time}ms${c.reset}`);\n this.blank();\n },\n};\n\nexport default logger;\n","/**\n * Velix v5 — Build Script\n * Build the application for production\n */\n\nimport { build } from '../build/index.js';\nimport logger from '../logger.js';\n\nbuild().catch(err => {\n logger.error('Build failed', err);\n process.exit(1);\n});\n"],"mappings":"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","names":["fs","path","fs","path","fs","path","fs","path","fs","path","fs","path","path","fs"]}
1
+ {"version":3,"sources":["../../build/index.ts","../../config.ts","../../router/index.ts","../../utils.ts","../../version.ts","../../logger.ts","../../runtime/start-build.ts"],"sourcesContent":["/**\n * Velix v5 Build System\n * Production build using esbuild\n */\n\nimport esbuild from 'esbuild';\nimport fs from 'fs';\nimport path from 'path';\nimport { loadConfig, resolvePaths } from '../config.js';\nimport { buildRouteTree } from '../router/index.js';\nimport { ensureDir, cleanDir, findFiles, formatBytes, formatTime } from '../utils.js';\nimport logger from '../logger.js';\nimport { VERSION } from '../version.js';\n\nexport interface BuildOptions {\n projectRoot?: string;\n outDir?: string;\n minify?: boolean;\n sourcemap?: boolean;\n}\n\n/**\n * Build the Velix application for production\n */\nexport async function build(options: BuildOptions = {}) {\n const projectRoot = options.projectRoot || process.cwd();\n const config = await loadConfig(projectRoot);\n const resolved = resolvePaths(config, projectRoot);\n\n const outDir = options.outDir || resolved.resolvedOutDir;\n const startTime = Date.now();\n\n logger.logo();\n logger.info('Building for production...');\n logger.blank();\n\n // Clean output directory\n cleanDir(outDir);\n\n const appDir = resolved.resolvedAppDir;\n const routes = buildRouteTree(appDir);\n\n // Collect all source files\n const sourceFiles = findFiles(appDir, /\\.(tsx?|jsx?)$/);\n\n if (sourceFiles.length === 0) {\n logger.warn('No source files found in app/ directory');\n return;\n }\n\n // Build server bundle\n try {\n const serverOutDir = path.join(outDir, 'server');\n ensureDir(serverOutDir);\n\n await esbuild.build({\n entryPoints: sourceFiles,\n outdir: serverOutDir,\n bundle: false,\n format: 'esm',\n platform: 'node',\n target: config.build.target,\n minify: options.minify ?? config.build.minify,\n sourcemap: options.sourcemap ?? config.build.sourcemap,\n jsx: 'automatic',\n logLevel: 'silent',\n treeShaking: true,\n legalComments: 'none',\n });\n\n logger.success('Server bundle built');\n } catch (err: any) {\n logger.error('Server build failed', err);\n process.exit(1);\n }\n\n // Build client bundle (client components and islands)\n try {\n const clientOutDir = path.join(outDir, 'client');\n ensureDir(clientOutDir);\n\n const clientFiles = sourceFiles.filter(f => {\n const content = fs.readFileSync(f, 'utf-8');\n const firstLine = content.split('\\n')[0]?.trim();\n return firstLine === \"'use client'\" || firstLine === '\"use client\"' ||\n firstLine === \"'use island'\" || firstLine === '\"use island\"';\n });\n\n if (clientFiles.length > 0) {\n await esbuild.build({\n entryPoints: clientFiles,\n outdir: clientOutDir,\n bundle: true,\n format: 'esm',\n platform: 'browser',\n target: ['es2022'],\n minify: options.minify ?? config.build.minify,\n sourcemap: options.sourcemap ?? config.build.sourcemap,\n splitting: config.build.splitting,\n jsx: 'automatic',\n logLevel: 'silent',\n external: ['react', 'react-dom'],\n treeShaking: true,\n legalComments: 'none',\n drop: options.minify ?? config.build.minify ? ['console', 'debugger'] : [],\n chunkNames: 'chunks/[name]-[hash]',\n });\n\n logger.success(`Client bundle built (${clientFiles.length} components)`);\n }\n } catch (err: any) {\n logger.error('Client build failed', err);\n process.exit(1);\n }\n\n // Copy public directory\n const publicDir = resolved.resolvedPublicDir;\n if (fs.existsSync(publicDir)) {\n const publicOutDir = path.join(outDir, 'public');\n ensureDir(publicOutDir);\n copyDirRecursive(publicDir, publicOutDir);\n logger.success('Static assets copied');\n }\n\n // Generate build manifest\n const manifest = {\n version: VERSION,\n buildTime: new Date().toISOString(),\n routes: routes.appRoutes.map(r => ({\n path: r.path,\n type: r.path.includes(':') ? 'dynamic' : 'static',\n })),\n api: routes.api.map(r => ({ path: r.path })),\n };\n\n fs.writeFileSync(path.join(outDir, 'manifest.json'), JSON.stringify(manifest, null, 2));\n\n const elapsed = Date.now() - startTime;\n const totalSize = getDirSize(outDir);\n\n logger.blank();\n logger.divider();\n logger.blank();\n\n // Log routes\n routes.appRoutes.forEach(r => {\n const type = r.path.includes(':') || r.path.includes('*') ? 'dynamic' : 'static';\n logger.route(r.path, type);\n });\n routes.api.forEach(r => logger.route(r.path, 'api'));\n\n logger.blank();\n logger.build({ time: elapsed });\n logger.info(`Output: ${outDir} (${formatBytes(totalSize)})`);\n logger.blank();\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction copyDirRecursive(src: string, dest: string) {\n ensureDir(dest);\n const entries = fs.readdirSync(src, { withFileTypes: true });\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) copyDirRecursive(srcPath, destPath);\n else fs.copyFileSync(srcPath, destPath);\n }\n}\n\nfunction getDirSize(dir: string): number {\n let size = 0;\n if (!fs.existsSync(dir)) return size;\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) size += getDirSize(fullPath);\n else size += fs.statSync(fullPath).size;\n }\n return size;\n}\n\nexport default { build };\n","/**\n * Velix v5 Configuration System\n * Handles loading, validation, and merging of velix.config.ts\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport { pathToFileURL } from 'url';\nimport { z } from 'zod';\nimport pc from 'picocolors';\n\n// ============================================================================\n// Configuration Schema (Zod validation)\n// ============================================================================\n\nconst AppConfigSchema = z.object({\n name: z.string().default('Velix App'),\n url: z.string().url().optional(),\n}).default({});\n\nconst ServerConfigSchema = z.object({\n port: z.number().min(1).max(65535).default(3000),\n host: z.string().default('localhost'),\n}).default({});\n\nconst RoutingConfigSchema = z.object({\n trailingSlash: z.boolean().default(false),\n}).default({});\n\nconst SEOConfigSchema = z.object({\n sitemap: z.boolean().default(true),\n robots: z.boolean().default(true),\n openGraph: z.boolean().default(true),\n}).default({});\n\nconst BuildConfigSchema = z.object({\n target: z.string().default('es2022'),\n minify: z.boolean().default(true),\n sourcemap: z.boolean().default(true),\n splitting: z.boolean().default(true),\n outDir: z.string().default('.velix'),\n}).default({});\n\nconst ExperimentalConfigSchema = z.object({\n islands: z.boolean().default(true),\n streaming: z.boolean().default(true),\n}).default({});\n\nconst PluginSchema = z.union([\n z.string(),\n z.object({\n name: z.string()\n }).passthrough(),\n]);\n\nexport const VelixConfigSchema = z.object({\n // App identity\n app: AppConfigSchema,\n\n // DevTools toggle\n devtools: z.boolean().default(true),\n\n // Server options\n server: ServerConfigSchema,\n\n // Routing options\n routing: RoutingConfigSchema,\n\n // SEO configuration\n seo: SEOConfigSchema,\n\n // Build options\n build: BuildConfigSchema,\n\n // Experimental features\n experimental: ExperimentalConfigSchema,\n\n // Plugins\n plugins: z.array(PluginSchema).default([]),\n\n // Directories (resolved automatically)\n appDir: z.string().default('app'),\n publicDir: z.string().default('public'),\n\n // Stylesheets\n styles: z.array(z.string()).default([]),\n\n // Favicon\n favicon: z.string().nullable().default(null),\n});\n\nexport type VelixConfig = z.infer<typeof VelixConfigSchema>;\n\n// ============================================================================\n// Default configuration\n// ============================================================================\n\nexport const defaultConfig: VelixConfig = VelixConfigSchema.parse({});\n\n// ============================================================================\n// defineConfig helper\n// ============================================================================\n\n/**\n * Helper function to define configuration with full type support.\n * Use this in your velix.config.ts file.\n *\n * @example\n * ```ts\n * import { defineConfig } from \"velix\";\n *\n * export default defineConfig({\n * app: { name: \"My App\" },\n * server: { port: 3000 },\n * seo: { sitemap: true }\n * });\n * ```\n */\nexport function defineConfig(config: Partial<VelixConfig>): Partial<VelixConfig> {\n return config;\n}\n\n// ============================================================================\n// Config Loader\n// ============================================================================\n\n/**\n * Loads and validates configuration from velix.config.ts\n */\nexport async function loadConfig(projectRoot: string): Promise<VelixConfig> {\n const configPathTs = path.join(projectRoot, 'velix.config.ts');\n const configPathJs = path.join(projectRoot, 'velix.config.js');\n // Support legacy config for migration\n const configPathLegacyTs = path.join(projectRoot, 'flexireact.config.ts');\n const configPathLegacyJs = path.join(projectRoot, 'flexireact.config.js');\n\n let configPath: string | null = null;\n if (fs.existsSync(configPathTs)) configPath = configPathTs;\n else if (fs.existsSync(configPathJs)) configPath = configPathJs;\n else if (fs.existsSync(configPathLegacyTs)) configPath = configPathLegacyTs;\n else if (fs.existsSync(configPathLegacyJs)) configPath = configPathLegacyJs;\n\n let userConfig: Partial<VelixConfig> = {};\n\n if (configPath) {\n try {\n const configUrl = pathToFileURL(configPath).href;\n const module = await import(`${configUrl}?t=${Date.now()}`);\n userConfig = module.default || module;\n } catch (error: any) {\n console.warn(pc.yellow(`⚠ Failed to load config: ${error.message}`));\n }\n }\n\n // Merge and validate with Zod\n const merged = deepMerge(defaultConfig, userConfig as Record<string, any>);\n\n try {\n return VelixConfigSchema.parse(merged);\n } catch (err: unknown) {\n if (err instanceof z.ZodError) {\n console.error(pc.red('✖ Configuration validation failed:'));\n for (const issue of err.issues) {\n console.error(pc.dim(` - ${issue.path.join('.')}: ${issue.message}`));\n }\n process.exit(1);\n }\n throw err;\n }\n}\n\n// ============================================================================\n// Path Resolution\n// ============================================================================\n\n/**\n * Resolves all paths in config relative to project root\n */\nexport function resolvePaths(config: VelixConfig, projectRoot: string): VelixConfig & { resolvedAppDir: string; resolvedPublicDir: string; resolvedOutDir: string } {\n return {\n ...config,\n resolvedAppDir: path.resolve(projectRoot, config.appDir),\n resolvedPublicDir: path.resolve(projectRoot, config.publicDir),\n resolvedOutDir: path.resolve(projectRoot, config.build.outDir),\n };\n}\n\n// ============================================================================\n// Utility: Deep merge\n// ============================================================================\n\nfunction deepMerge(target: Record<string, any>, source: Record<string, any>): Record<string, any> {\n const result = { ...target };\n\n for (const key in source) {\n if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {\n result[key] = deepMerge(target[key] || {}, source[key]);\n } else {\n result[key] = source[key];\n }\n }\n\n return result;\n}\n","/**\n * Velix v5 Router\n * File-based routing using the app/ directory convention\n *\n * Supports:\n * - app/page.tsx → /\n * - app/dashboard/page.tsx → /dashboard\n * - app/blog/[slug]/page.tsx → /blog/:slug\n * - app/(group)/page.tsx → / (route groups)\n * - app/[...slug]/page.tsx → catch-all routes\n * - layout.tsx, loading.tsx, error.tsx, not-found.tsx\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport { isServerComponent, isClientComponent, isIsland } from '../utils.js';\nimport type { Route, RouteTree as TypedRouteTree, RouteTreeNode } from '../types.js';\n\n// ============================================================================\n// Route Types\n// ============================================================================\n\nexport const RouteType = {\n PAGE: 'page',\n API: 'api',\n LAYOUT: 'layout',\n LOADING: 'loading',\n ERROR: 'error',\n NOT_FOUND: 'not-found'\n} as const;\n\n// ============================================================================\n// Build Route Tree\n// ============================================================================\n\n/**\n * Builds the complete route tree from the app/ directory\n */\nexport function buildRouteTree(appDir: string) {\n const projectRoot = path.dirname(appDir);\n\n const routes: {\n pages: Route[];\n api: Route[];\n layouts: Map<string, string>;\n tree: RouteTreeNode;\n appRoutes: Route[];\n rootLayout?: string;\n } = {\n pages: [],\n api: [],\n layouts: new Map(),\n tree: { children: {}, routes: [] },\n appRoutes: [],\n };\n\n // Scan app/ directory\n if (fs.existsSync(appDir)) {\n scanAppDirectory(appDir, appDir, routes);\n }\n\n // Scan server/api/ for API routes\n const serverApiDir = path.join(projectRoot, 'server', 'api');\n if (fs.existsSync(serverApiDir)) {\n scanApiDirectory(serverApiDir, serverApiDir, routes);\n }\n\n // Check for root layout\n const rootLayoutTsx = path.join(appDir, 'layout.tsx');\n const rootLayoutJsx = path.join(appDir, 'layout.jsx');\n if (fs.existsSync(rootLayoutTsx)) routes.rootLayout = rootLayoutTsx;\n else if (fs.existsSync(rootLayoutJsx)) routes.rootLayout = rootLayoutJsx;\n\n // Build route tree for nested routes\n routes.tree = buildTree(routes.appRoutes);\n\n return routes;\n}\n\n// ============================================================================\n// App Directory Scanner\n// ============================================================================\n\n/**\n * Scans app/ directory for file-based routing\n * Supports: page.tsx, layout.tsx, loading.tsx, error.tsx, not-found.tsx, [param].tsx\n */\nfunction scanAppDirectory(\n baseDir: string,\n currentDir: string,\n routes: { appRoutes: Route[] },\n parentSegments: string[] = [],\n parentLayout: string | null = null,\n parentMiddleware: string | null = null\n) {\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\n\n // Find special files in current directory\n const specialFiles: Record<string, string | null> = {\n page: null,\n layout: null,\n loading: null,\n error: null,\n notFound: null,\n template: null,\n middleware: null\n };\n\n for (const entry of entries) {\n if (entry.isFile()) {\n const name = entry.name.replace(/\\.(jsx|js|tsx|ts)$/, '');\n const fullPath = path.join(currentDir, entry.name);\n const ext = path.extname(entry.name);\n\n // Only process relevant extensions\n if (!['.tsx', '.jsx', '.ts', '.js'].includes(ext)) continue;\n\n if (name === 'page') specialFiles.page = fullPath;\n if (name === 'layout') specialFiles.layout = fullPath;\n if (name === 'loading') specialFiles.loading = fullPath;\n if (name === 'error') specialFiles.error = fullPath;\n if (name === 'not-found') specialFiles.notFound = fullPath;\n if (name === 'template') specialFiles.template = fullPath;\n if (name === 'middleware' || name === '_middleware') specialFiles.middleware = fullPath;\n\n // Handle [param].tsx files directly in app/ (alternative to [param]/page.tsx)\n if (name.startsWith('[') && name.endsWith(']') && ['.tsx', '.jsx'].includes(ext)) {\n const paramName = name.slice(1, -1);\n let segmentName: string;\n\n if (paramName.startsWith('...')) {\n segmentName = '*' + paramName.slice(3);\n } else {\n segmentName = ':' + paramName;\n }\n\n const routePath = '/' + [...parentSegments, segmentName].join('/');\n\n routes.appRoutes.push({\n type: RouteType.PAGE,\n path: routePath.replace(/\\/+/g, '/'),\n filePath: fullPath,\n pattern: createRoutePattern(routePath),\n segments: [...parentSegments, segmentName],\n layout: specialFiles.layout || parentLayout,\n loading: specialFiles.loading,\n error: specialFiles.error,\n notFound: specialFiles.notFound,\n template: specialFiles.template,\n middleware: specialFiles.middleware || parentMiddleware,\n isServerComponent: isServerComponent(fullPath),\n isClientComponent: isClientComponent(fullPath),\n isIsland: isIsland(fullPath),\n });\n }\n }\n }\n\n // If there's a page.tsx, create a route for this directory\n if (specialFiles.page) {\n const routePath = '/' + parentSegments.join('/') || '/';\n\n routes.appRoutes.push({\n type: RouteType.PAGE,\n path: routePath.replace(/\\/+/g, '/') || '/',\n filePath: specialFiles.page,\n pattern: createRoutePattern(routePath || '/'),\n segments: parentSegments,\n layout: specialFiles.layout || parentLayout,\n loading: specialFiles.loading,\n error: specialFiles.error,\n notFound: specialFiles.notFound,\n template: specialFiles.template,\n middleware: specialFiles.middleware || parentMiddleware,\n isServerComponent: isServerComponent(specialFiles.page),\n isClientComponent: isClientComponent(specialFiles.page),\n isIsland: isIsland(specialFiles.page),\n });\n }\n\n // Recursively scan subdirectories\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const fullPath = path.join(currentDir, entry.name);\n\n // Skip special directories\n if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue;\n\n // Handle route groups (parentheses) — don't add to URL\n const isGroup = entry.name.startsWith('(') && entry.name.endsWith(')');\n\n // Handle dynamic segments [param]\n let segmentName = entry.name;\n if (entry.name.startsWith('[') && entry.name.endsWith(']')) {\n segmentName = ':' + entry.name.slice(1, -1);\n if (entry.name.startsWith('[...')) {\n segmentName = '*' + entry.name.slice(4, -1);\n }\n if (entry.name.startsWith('[[...')) {\n segmentName = '*' + entry.name.slice(5, -2);\n }\n }\n\n const newSegments = isGroup ? parentSegments : [...parentSegments, segmentName];\n const newLayout = specialFiles.layout || parentLayout;\n const newMiddleware = specialFiles.middleware || parentMiddleware;\n\n scanAppDirectory(baseDir, fullPath, routes, newSegments, newLayout, newMiddleware);\n }\n }\n}\n\n// ============================================================================\n// API Directory Scanner (server/api/)\n// ============================================================================\n\nfunction scanApiDirectory(baseDir: string, currentDir: string, routes: { api: Route[] }, parentSegments: string[] = []) {\n const entries = fs.readdirSync(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n\n if (entry.isDirectory()) {\n scanApiDirectory(baseDir, fullPath, routes, [...parentSegments, entry.name]);\n } else if (entry.isFile()) {\n const ext = path.extname(entry.name);\n if (!['.ts', '.js'].includes(ext)) continue;\n\n const baseName = path.basename(entry.name, ext);\n // route.ts maps to the parent path, other names become segments\n const apiSegments = baseName === 'route' || baseName === 'index'\n ? parentSegments\n : [...parentSegments, baseName];\n\n const apiPath = '/api/' + apiSegments.join('/');\n\n routes.api.push({\n type: RouteType.API,\n path: apiPath.replace(/\\/+/g, '/') || '/api',\n filePath: fullPath,\n pattern: createRoutePattern(apiPath),\n segments: ['api', ...apiSegments].filter(Boolean),\n });\n }\n }\n}\n\n// ============================================================================\n// Route Matching\n// ============================================================================\n\n/**\n * Creates regex pattern for route matching\n */\nfunction createRoutePattern(routePath: string): RegExp {\n let pattern = routePath\n .replace(/\\*[^/]*/g, '(.*)') // Catch-all\n .replace(/:[^/]+/g, '([^/]+)') // Dynamic segments\n .replace(/\\//g, '\\\\/');\n\n return new RegExp(`^${pattern}$`);\n}\n\n/**\n * Matches URL path against routes\n */\nexport function matchRoute(urlPath: string, routes: Route[]) {\n const normalizedPath = urlPath === '' ? '/' : urlPath.split('?')[0];\n\n for (const route of routes) {\n const match = normalizedPath.match(route.pattern);\n if (match) {\n const params = extractParams(route.path, match);\n return { ...route, params };\n }\n }\n\n return null;\n}\n\n/**\n * Extracts parameters from route match\n */\nfunction extractParams(routePath: string, match: RegExpMatchArray): Record<string, string> {\n const params: Record<string, string> = {};\n const paramNames: string[] = [];\n\n const paramRegex = /:([^/]+)|\\*([^/]*)/g;\n let paramMatch;\n while ((paramMatch = paramRegex.exec(routePath)) !== null) {\n paramNames.push(paramMatch[1] || paramMatch[2] || 'splat');\n }\n\n paramNames.forEach((name, index) => {\n params[name] = match[index + 1];\n });\n\n return params;\n}\n\n// ============================================================================\n// Layout Resolution\n// ============================================================================\n\n/**\n * Finds all layouts that apply to a route\n */\nexport function findRouteLayouts(route: Route, layoutsMap: Map<string, string>): Array<{ name: string; filePath: string | undefined }> {\n const layouts: Array<{ name: string; filePath: string | undefined }> = [];\n\n // Check for segment-based layouts\n for (const segment of route.segments) {\n if (layoutsMap.has(segment)) {\n layouts.push({ name: segment, filePath: layoutsMap.get(segment) });\n }\n }\n\n // Check for route-specific layout\n if (route.layout) {\n layouts.push({ name: 'route', filePath: route.layout });\n }\n\n // Check for root layout\n if (layoutsMap.has('root')) {\n layouts.unshift({ name: 'root', filePath: layoutsMap.get('root') });\n }\n\n return layouts;\n}\n\n// ============================================================================\n// Tree Building\n// ============================================================================\n\nfunction buildTree(routes: Route[]): RouteTreeNode {\n const tree: RouteTreeNode = { children: {}, routes: [] };\n\n for (const route of routes) {\n let current = tree;\n for (const segment of route.segments) {\n if (!current.children[segment]) {\n current.children[segment] = { children: {}, routes: [] };\n }\n current = current.children[segment];\n }\n current.routes.push(route);\n }\n\n return tree;\n}\n\n// ============================================================================\n// Default Export\n// ============================================================================\n\nexport default {\n buildRouteTree,\n matchRoute,\n findRouteLayouts,\n RouteType\n};\n","/**\n * Velix v5 Utility Functions\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport crypto from 'crypto';\n\n/**\n * Generates a unique hash for cache busting\n */\nexport function generateHash(content: string): string {\n return crypto.createHash('md5').update(content).digest('hex').slice(0, 8);\n}\n\n/**\n * Escapes HTML special characters\n */\nexport function escapeHtml(str: string): string {\n const htmlEntities: Record<string, string> = {\n '&': '&amp;', '<': '&lt;', '>': '&gt;',\n '\"': '&quot;', \"'\": '&#39;'\n };\n return String(str).replace(/[&<>\"']/g, char => htmlEntities[char]);\n}\n\n/**\n * Recursively finds all files matching a pattern\n */\nexport function findFiles(dir: string, pattern: RegExp, files: string[] = []): string[] {\n if (!fs.existsSync(dir)) return files;\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) findFiles(fullPath, pattern, files);\n else if (pattern.test(entry.name)) files.push(fullPath);\n }\n return files;\n}\n\n/**\n * Ensures a directory exists\n */\nexport function ensureDir(dir: string): void {\n if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });\n}\n\n/**\n * Cleans a directory\n */\nexport function cleanDir(dir: string): void {\n if (fs.existsSync(dir)) fs.rmSync(dir, { recursive: true, force: true });\n fs.mkdirSync(dir, { recursive: true });\n}\n\n/**\n * Copies a directory recursively\n */\nexport function copyDir(src: string, dest: string): void {\n ensureDir(dest);\n const entries = fs.readdirSync(src, { withFileTypes: true });\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) copyDir(srcPath, destPath);\n else fs.copyFileSync(srcPath, destPath);\n }\n}\n\n/**\n * Debounce function for file watching\n */\nexport function debounce<T extends (...args: unknown[]) => unknown>(fn: T, delay: number): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n return (...args: Parameters<T>) => {\n clearTimeout(timeout);\n timeout = setTimeout(() => fn(...args), delay);\n };\n}\n\n/**\n * Formats bytes to human-readable string\n */\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];\n}\n\n/**\n * Formats milliseconds to human-readable string\n */\nexport function formatTime(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n return `${(ms / 1000).toFixed(2)}s`;\n}\n\n/**\n * Creates a deferred promise\n */\nexport function createDeferred<T>() {\n let resolve: (value: T | PromiseLike<T>) => void;\n let reject: (reason?: unknown) => void;\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n return { promise, resolve: resolve!, reject: reject! };\n}\n\n/**\n * Sleep utility\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Check if a file is a server component (has 'use server' directive)\n */\nexport function isServerComponent(filePath: string): boolean {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const firstLine = content.split('\\n')[0].trim();\n return firstLine === \"'use server'\" || firstLine === '\"use server\"';\n } catch { return false; }\n}\n\n/**\n * Check if a file is a client component (has 'use client' directive)\n */\nexport function isClientComponent(filePath: string): boolean {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const firstLine = content.split('\\n')[0].trim();\n return firstLine === \"'use client'\" || firstLine === '\"use client\"';\n } catch { return false; }\n}\n\n/**\n * Check if a component is an island (has 'use island' directive)\n */\nexport function isIsland(filePath: string): boolean {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const firstLine = content.split('\\n')[0].trim();\n return firstLine === \"'use island'\" || firstLine === '\"use island\"';\n } catch { return false; }\n}\n","/**\n * Velix version — single source of truth.\n * Update this file only when releasing a new version.\n */\nexport const VERSION = '5.2.3';\n","/**\n * Velix v5 Logger\n * Minimalist, professional output inspired by modern CLIs\n */\n\nimport { VERSION } from './version.js';\n\nconst colors = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n magenta: '\\x1b[35m',\n cyan: '\\x1b[36m',\n white: '\\x1b[37m',\n gray: '\\x1b[90m',\n};\n\nconst c = colors;\n\nfunction getTime() {\n const now = new Date();\n const hours = String(now.getHours()).padStart(2, '0');\n const minutes = String(now.getMinutes()).padStart(2, '0');\n const seconds = String(now.getSeconds()).padStart(2, '0');\n return `${c.dim}${hours}:${minutes}:${seconds}${c.reset}`;\n}\n\nfunction getStatusColor(status: number) {\n if (status >= 500) return c.red;\n if (status >= 400) return c.yellow;\n if (status >= 300) return c.cyan;\n if (status >= 200) return c.green;\n return c.white;\n}\n\nfunction fmtTime(ms: number) {\n if (ms < 1) return `${c.gray}<1ms${c.reset}`;\n if (ms < 100) return `${c.green}${ms}ms${c.reset}`;\n if (ms < 500) return `${c.yellow}${ms}ms${c.reset}`;\n return `${c.red}${ms}ms${c.reset}`;\n}\n\nconst LOGO = `\n ${c.cyan}▲${c.reset} ${c.bold}Velix${c.reset} ${c.dim}v${VERSION}${c.reset}\n`;\n\nexport const logger = {\n logo() {\n console.log(LOGO);\n console.log(`${c.dim} ──────────────────────────────────────────────${c.reset}`);\n console.log('');\n },\n\n serverStart(config: { port: number | string; host: string; mode: string; pagesDir?: string }, startTime = Date.now()) {\n const { port, host, mode, pagesDir } = config;\n const elapsed = Date.now() - startTime;\n\n console.log(LOGO);\n console.log(` ${c.green}✔${c.reset} ${c.bold}Ready${c.reset} in ${elapsed}ms`);\n console.log('');\n console.log(` ${c.bold}Local:${c.reset} ${c.cyan}http://${host}:${port}${c.reset}`);\n console.log(` ${c.bold}Mode:${c.reset} ${mode === 'development' ? c.yellow : c.green}${mode}${c.reset}`);\n if (pagesDir) console.log(` ${c.bold}App:${c.reset} ${c.dim}${pagesDir}${c.reset}`);\n console.log('');\n },\n\n request(method: string, path: string, status: number, time: number, extra: { type?: string } = {}) {\n const statusColor = getStatusColor(status);\n const timeStr = fmtTime(time);\n\n let badge = `${c.dim}○${c.reset}`;\n if (extra.type === 'dynamic' || extra.type === 'ssr') badge = `${c.white}ƒ${c.reset}`;\n else if (extra.type === 'api') badge = `${c.cyan}λ${c.reset}`;\n\n const statusStr = `${statusColor}${status}${c.reset}`;\n console.log(` ${badge} ${c.white}${method}${c.reset} ${path} ${statusStr} ${c.dim}${timeStr}${c.reset}`);\n },\n\n info(msg: string) { console.log(` ${c.cyan}ℹ${c.reset} ${msg}`); },\n success(msg: string) { console.log(` ${c.green}✔${c.reset} ${msg}`); },\n warn(msg: string) { console.log(` ${c.yellow}⚠${c.reset} ${c.yellow}${msg}${c.reset}`); },\n\n error(msg: string, err: Error | null = null) {\n console.log(` ${c.red}✖${c.reset} ${c.red}${msg}${c.reset}`);\n if (err?.stack) {\n console.log('');\n console.log(`${c.dim}${err.stack.split('\\n').slice(1, 4).join('\\n')}${c.reset}`);\n console.log('');\n }\n },\n\n compile(file: string, time: number) {\n console.log(` ${c.white}●${c.reset} Compiling ${c.dim}${file}${c.reset} ${c.dim}(${time}ms)${c.reset}`);\n },\n\n hmr(file: string) {\n console.log(` ${c.green}↻${c.reset} Fast Refresh ${c.dim}${file}${c.reset}`);\n },\n\n plugin(name: string) {\n console.log(` ${c.cyan}◆${c.reset} Plugin ${c.dim}${name}${c.reset}`);\n },\n\n route(path: string, type: string) {\n const typeLabel = type === 'api' ? 'λ' : type === 'dynamic' ? 'ƒ' : '○';\n const color = type === 'api' ? c.cyan : type === 'dynamic' ? c.white : c.dim;\n console.log(` ${color}${typeLabel}${c.reset} ${path}`);\n },\n\n divider() { console.log(`${c.dim} ──────────────────────────────────────────────${c.reset}`); },\n blank() { console.log(''); },\n\n portInUse(port: number | string) {\n this.error(`Port ${port} is already in use.`);\n this.blank();\n console.log(` ${c.dim}Try:${c.reset}`);\n console.log(` 1. Kill the process on port ${port}`);\n console.log(` 2. Use a different port via PORT env var`);\n this.blank();\n },\n\n build(stats: { time: number }) {\n this.blank();\n console.log(` ${c.green}✔${c.reset} Build completed`);\n this.blank();\n console.log(` ${c.dim}Total time:${c.reset} ${c.white}${stats.time}ms${c.reset}`);\n this.blank();\n },\n};\n\nexport default logger;\n","/**\n * Velix v5 — Build Script\n * Build the application for production\n */\n\nimport { build } from '../build/index.js';\nimport logger from '../logger.js';\n\nbuild().catch(err => {\n logger.error('Build failed', err);\n process.exit(1);\n});\n"],"mappings":";AAKA,OAAO,aAAa;AACpB,OAAOA,SAAQ;AACf,OAAOC,WAAU;;;ACFjB,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAC9B,SAAS,SAAS;AAClB,OAAO,QAAQ;AAMf,IAAM,kBAAkB,EAAE,OAAO;AAAA,EAC/B,MAAM,EAAE,OAAO,EAAE,QAAQ,WAAW;AAAA,EACpC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AACjC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAEb,IAAM,qBAAqB,EAAE,OAAO;AAAA,EAClC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,KAAK,EAAE,QAAQ,GAAI;AAAA,EAC/C,MAAM,EAAE,OAAO,EAAE,QAAQ,WAAW;AACtC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAEb,IAAM,sBAAsB,EAAE,OAAO;AAAA,EACnC,eAAe,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAC1C,CAAC,EAAE,QAAQ,CAAC,CAAC;AAEb,IAAM,kBAAkB,EAAE,OAAO;AAAA,EAC/B,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACjC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAChC,WAAW,EAAE,QAAQ,EAAE,QAAQ,IAAI;AACrC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAEb,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACjC,QAAQ,EAAE,OAAO,EAAE,QAAQ,QAAQ;AAAA,EACnC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAChC,WAAW,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACnC,WAAW,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACnC,QAAQ,EAAE,OAAO,EAAE,QAAQ,QAAQ;AACrC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAEb,IAAM,2BAA2B,EAAE,OAAO;AAAA,EACxC,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EACjC,WAAW,EAAE,QAAQ,EAAE,QAAQ,IAAI;AACrC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAEb,IAAM,eAAe,EAAE,MAAM;AAAA,EAC3B,EAAE,OAAO;AAAA,EACT,EAAE,OAAO;AAAA,IACP,MAAM,EAAE,OAAO;AAAA,EACjB,CAAC,EAAE,YAAY;AACjB,CAAC;AAEM,IAAM,oBAAoB,EAAE,OAAO;AAAA;AAAA,EAExC,KAAK;AAAA;AAAA,EAGL,UAAU,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA;AAAA,EAGlC,QAAQ;AAAA;AAAA,EAGR,SAAS;AAAA;AAAA,EAGT,KAAK;AAAA;AAAA,EAGL,OAAO;AAAA;AAAA,EAGP,cAAc;AAAA;AAAA,EAGd,SAAS,EAAE,MAAM,YAAY,EAAE,QAAQ,CAAC,CAAC;AAAA;AAAA,EAGzC,QAAQ,EAAE,OAAO,EAAE,QAAQ,KAAK;AAAA,EAChC,WAAW,EAAE,OAAO,EAAE,QAAQ,QAAQ;AAAA;AAAA,EAGtC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA;AAAA,EAGtC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,IAAI;AAC7C,CAAC;AAQM,IAAM,gBAA6B,kBAAkB,MAAM,CAAC,CAAC;AAgCpE,eAAsB,WAAW,aAA2C;AAC1E,QAAM,eAAe,KAAK,KAAK,aAAa,iBAAiB;AAC7D,QAAM,eAAe,KAAK,KAAK,aAAa,iBAAiB;AAE7D,QAAM,qBAAqB,KAAK,KAAK,aAAa,sBAAsB;AACxE,QAAM,qBAAqB,KAAK,KAAK,aAAa,sBAAsB;AAExE,MAAI,aAA4B;AAChC,MAAI,GAAG,WAAW,YAAY,EAAG,cAAa;AAAA,WACrC,GAAG,WAAW,YAAY,EAAG,cAAa;AAAA,WAC1C,GAAG,WAAW,kBAAkB,EAAG,cAAa;AAAA,WAChD,GAAG,WAAW,kBAAkB,EAAG,cAAa;AAEzD,MAAI,aAAmC,CAAC;AAExC,MAAI,YAAY;AACd,QAAI;AACF,YAAM,YAAY,cAAc,UAAU,EAAE;AAC5C,YAAM,SAAS,MAAM,OAAO,GAAG,SAAS,MAAM,KAAK,IAAI,CAAC;AACxD,mBAAa,OAAO,WAAW;AAAA,IACjC,SAAS,OAAY;AACnB,cAAQ,KAAK,GAAG,OAAO,iCAA4B,MAAM,OAAO,EAAE,CAAC;AAAA,IACrE;AAAA,EACF;AAGA,QAAM,SAAS,UAAU,eAAe,UAAiC;AAEzE,MAAI;AACF,WAAO,kBAAkB,MAAM,MAAM;AAAA,EACvC,SAAS,KAAc;AACrB,QAAI,eAAe,EAAE,UAAU;AAC7B,cAAQ,MAAM,GAAG,IAAI,yCAAoC,CAAC;AAC1D,iBAAW,SAAS,IAAI,QAAQ;AAC9B,gBAAQ,MAAM,GAAG,IAAI,OAAO,MAAM,KAAK,KAAK,GAAG,CAAC,KAAK,MAAM,OAAO,EAAE,CAAC;AAAA,MACvE;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM;AAAA,EACR;AACF;AASO,SAAS,aAAa,QAAqB,aAAkH;AAClK,SAAO;AAAA,IACL,GAAG;AAAA,IACH,gBAAgB,KAAK,QAAQ,aAAa,OAAO,MAAM;AAAA,IACvD,mBAAmB,KAAK,QAAQ,aAAa,OAAO,SAAS;AAAA,IAC7D,gBAAgB,KAAK,QAAQ,aAAa,OAAO,MAAM,MAAM;AAAA,EAC/D;AACF;AAMA,SAAS,UAAU,QAA6B,QAAkD;AAChG,QAAM,SAAS,EAAE,GAAG,OAAO;AAE3B,aAAW,OAAO,QAAQ;AACxB,QAAI,OAAO,GAAG,KAAK,OAAO,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,QAAQ,OAAO,GAAG,CAAC,GAAG;AACjF,aAAO,GAAG,IAAI,UAAU,OAAO,GAAG,KAAK,CAAC,GAAG,OAAO,GAAG,CAAC;AAAA,IACxD,OAAO;AACL,aAAO,GAAG,IAAI,OAAO,GAAG;AAAA,IAC1B;AAAA,EACF;AAEA,SAAO;AACT;;;AC9LA,OAAOC,SAAQ;AACf,OAAOC,WAAU;;;ACVjB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AAwBV,SAAS,UAAU,KAAa,SAAiB,QAAkB,CAAC,GAAa;AACtF,MAAI,CAACC,IAAG,WAAW,GAAG,EAAG,QAAO;AAChC,QAAM,UAAUA,IAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAC3D,aAAW,SAAS,SAAS;AAC3B,UAAM,WAAWC,MAAK,KAAK,KAAK,MAAM,IAAI;AAC1C,QAAI,MAAM,YAAY,EAAG,WAAU,UAAU,SAAS,KAAK;AAAA,aAClD,QAAQ,KAAK,MAAM,IAAI,EAAG,OAAM,KAAK,QAAQ;AAAA,EACxD;AACA,SAAO;AACT;AAKO,SAAS,UAAU,KAAmB;AAC3C,MAAI,CAACD,IAAG,WAAW,GAAG,EAAG,CAAAA,IAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAChE;AAKO,SAAS,SAAS,KAAmB;AAC1C,MAAIA,IAAG,WAAW,GAAG,EAAG,CAAAA,IAAG,OAAO,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACvE,EAAAA,IAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AACvC;AA8BO,SAAS,YAAY,OAAuB;AACjD,MAAI,UAAU,EAAG,QAAO;AACxB,QAAM,IAAI;AACV,QAAM,QAAQ,CAAC,KAAK,MAAM,MAAM,IAAI;AACpC,QAAM,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC;AAClD,SAAO,YAAY,QAAQ,KAAK,IAAI,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,MAAM,MAAM,CAAC;AACxE;AAiCO,SAAS,kBAAkB,UAA2B;AAC3D,MAAI;AACF,UAAM,UAAUE,IAAG,aAAa,UAAU,OAAO;AACjD,UAAM,YAAY,QAAQ,MAAM,IAAI,EAAE,CAAC,EAAE,KAAK;AAC9C,WAAO,cAAc,kBAAkB,cAAc;AAAA,EACvD,QAAQ;AAAE,WAAO;AAAA,EAAO;AAC1B;AAKO,SAAS,kBAAkB,UAA2B;AAC3D,MAAI;AACF,UAAM,UAAUA,IAAG,aAAa,UAAU,OAAO;AACjD,UAAM,YAAY,QAAQ,MAAM,IAAI,EAAE,CAAC,EAAE,KAAK;AAC9C,WAAO,cAAc,kBAAkB,cAAc;AAAA,EACvD,QAAQ;AAAE,WAAO;AAAA,EAAO;AAC1B;AAKO,SAAS,SAAS,UAA2B;AAClD,MAAI;AACF,UAAM,UAAUA,IAAG,aAAa,UAAU,OAAO;AACjD,UAAM,YAAY,QAAQ,MAAM,IAAI,EAAE,CAAC,EAAE,KAAK;AAC9C,WAAO,cAAc,kBAAkB,cAAc;AAAA,EACvD,QAAQ;AAAE,WAAO;AAAA,EAAO;AAC1B;;;ADhIO,IAAM,YAAY;AAAA,EACvB,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,OAAO;AAAA,EACP,WAAW;AACb;AASO,SAAS,eAAe,QAAgB;AAC7C,QAAM,cAAcC,MAAK,QAAQ,MAAM;AAEvC,QAAM,SAOF;AAAA,IACF,OAAO,CAAC;AAAA,IACR,KAAK,CAAC;AAAA,IACN,SAAS,oBAAI,IAAI;AAAA,IACjB,MAAM,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,EAAE;AAAA,IACjC,WAAW,CAAC;AAAA,EACd;AAGA,MAAIC,IAAG,WAAW,MAAM,GAAG;AACzB,qBAAiB,QAAQ,QAAQ,MAAM;AAAA,EACzC;AAGA,QAAM,eAAeD,MAAK,KAAK,aAAa,UAAU,KAAK;AAC3D,MAAIC,IAAG,WAAW,YAAY,GAAG;AAC/B,qBAAiB,cAAc,cAAc,MAAM;AAAA,EACrD;AAGA,QAAM,gBAAgBD,MAAK,KAAK,QAAQ,YAAY;AACpD,QAAM,gBAAgBA,MAAK,KAAK,QAAQ,YAAY;AACpD,MAAIC,IAAG,WAAW,aAAa,EAAG,QAAO,aAAa;AAAA,WAC7CA,IAAG,WAAW,aAAa,EAAG,QAAO,aAAa;AAG3D,SAAO,OAAO,UAAU,OAAO,SAAS;AAExC,SAAO;AACT;AAUA,SAAS,iBACP,SACA,YACA,QACA,iBAA2B,CAAC,GAC5B,eAA8B,MAC9B,mBAAkC,MAClC;AACA,QAAM,UAAUA,IAAG,YAAY,YAAY,EAAE,eAAe,KAAK,CAAC;AAGlE,QAAM,eAA8C;AAAA,IAClD,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AAEA,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,OAAO,GAAG;AAClB,YAAM,OAAO,MAAM,KAAK,QAAQ,sBAAsB,EAAE;AACxD,YAAM,WAAWD,MAAK,KAAK,YAAY,MAAM,IAAI;AACjD,YAAM,MAAMA,MAAK,QAAQ,MAAM,IAAI;AAGnC,UAAI,CAAC,CAAC,QAAQ,QAAQ,OAAO,KAAK,EAAE,SAAS,GAAG,EAAG;AAEnD,UAAI,SAAS,OAAQ,cAAa,OAAO;AACzC,UAAI,SAAS,SAAU,cAAa,SAAS;AAC7C,UAAI,SAAS,UAAW,cAAa,UAAU;AAC/C,UAAI,SAAS,QAAS,cAAa,QAAQ;AAC3C,UAAI,SAAS,YAAa,cAAa,WAAW;AAClD,UAAI,SAAS,WAAY,cAAa,WAAW;AACjD,UAAI,SAAS,gBAAgB,SAAS,cAAe,cAAa,aAAa;AAG/E,UAAI,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG,KAAK,CAAC,QAAQ,MAAM,EAAE,SAAS,GAAG,GAAG;AAChF,cAAM,YAAY,KAAK,MAAM,GAAG,EAAE;AAClC,YAAI;AAEJ,YAAI,UAAU,WAAW,KAAK,GAAG;AAC/B,wBAAc,MAAM,UAAU,MAAM,CAAC;AAAA,QACvC,OAAO;AACL,wBAAc,MAAM;AAAA,QACtB;AAEA,cAAM,YAAY,MAAM,CAAC,GAAG,gBAAgB,WAAW,EAAE,KAAK,GAAG;AAEjE,eAAO,UAAU,KAAK;AAAA,UACpB,MAAM,UAAU;AAAA,UAChB,MAAM,UAAU,QAAQ,QAAQ,GAAG;AAAA,UACnC,UAAU;AAAA,UACV,SAAS,mBAAmB,SAAS;AAAA,UACrC,UAAU,CAAC,GAAG,gBAAgB,WAAW;AAAA,UACzC,QAAQ,aAAa,UAAU;AAAA,UAC/B,SAAS,aAAa;AAAA,UACtB,OAAO,aAAa;AAAA,UACpB,UAAU,aAAa;AAAA,UACvB,UAAU,aAAa;AAAA,UACvB,YAAY,aAAa,cAAc;AAAA,UACvC,mBAAmB,kBAAkB,QAAQ;AAAA,UAC7C,mBAAmB,kBAAkB,QAAQ;AAAA,UAC7C,UAAU,SAAS,QAAQ;AAAA,QAC7B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,MAAI,aAAa,MAAM;AACrB,UAAM,YAAY,MAAM,eAAe,KAAK,GAAG,KAAK;AAEpD,WAAO,UAAU,KAAK;AAAA,MACpB,MAAM,UAAU;AAAA,MAChB,MAAM,UAAU,QAAQ,QAAQ,GAAG,KAAK;AAAA,MACxC,UAAU,aAAa;AAAA,MACvB,SAAS,mBAAmB,aAAa,GAAG;AAAA,MAC5C,UAAU;AAAA,MACV,QAAQ,aAAa,UAAU;AAAA,MAC/B,SAAS,aAAa;AAAA,MACtB,OAAO,aAAa;AAAA,MACpB,UAAU,aAAa;AAAA,MACvB,UAAU,aAAa;AAAA,MACvB,YAAY,aAAa,cAAc;AAAA,MACvC,mBAAmB,kBAAkB,aAAa,IAAI;AAAA,MACtD,mBAAmB,kBAAkB,aAAa,IAAI;AAAA,MACtD,UAAU,SAAS,aAAa,IAAI;AAAA,IACtC,CAAC;AAAA,EACH;AAGA,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,YAAY,GAAG;AACvB,YAAM,WAAWA,MAAK,KAAK,YAAY,MAAM,IAAI;AAGjD,UAAI,MAAM,KAAK,WAAW,GAAG,KAAK,MAAM,KAAK,WAAW,GAAG,EAAG;AAG9D,YAAM,UAAU,MAAM,KAAK,WAAW,GAAG,KAAK,MAAM,KAAK,SAAS,GAAG;AAGrE,UAAI,cAAc,MAAM;AACxB,UAAI,MAAM,KAAK,WAAW,GAAG,KAAK,MAAM,KAAK,SAAS,GAAG,GAAG;AAC1D,sBAAc,MAAM,MAAM,KAAK,MAAM,GAAG,EAAE;AAC1C,YAAI,MAAM,KAAK,WAAW,MAAM,GAAG;AACjC,wBAAc,MAAM,MAAM,KAAK,MAAM,GAAG,EAAE;AAAA,QAC5C;AACA,YAAI,MAAM,KAAK,WAAW,OAAO,GAAG;AAClC,wBAAc,MAAM,MAAM,KAAK,MAAM,GAAG,EAAE;AAAA,QAC5C;AAAA,MACF;AAEA,YAAM,cAAc,UAAU,iBAAiB,CAAC,GAAG,gBAAgB,WAAW;AAC9E,YAAM,YAAY,aAAa,UAAU;AACzC,YAAM,gBAAgB,aAAa,cAAc;AAEjD,uBAAiB,SAAS,UAAU,QAAQ,aAAa,WAAW,aAAa;AAAA,IACnF;AAAA,EACF;AACF;AAMA,SAAS,iBAAiB,SAAiB,YAAoB,QAA0B,iBAA2B,CAAC,GAAG;AACtH,QAAM,UAAUC,IAAG,YAAY,YAAY,EAAE,eAAe,KAAK,CAAC;AAElE,aAAW,SAAS,SAAS;AAC3B,UAAM,WAAWD,MAAK,KAAK,YAAY,MAAM,IAAI;AAEjD,QAAI,MAAM,YAAY,GAAG;AACvB,uBAAiB,SAAS,UAAU,QAAQ,CAAC,GAAG,gBAAgB,MAAM,IAAI,CAAC;AAAA,IAC7E,WAAW,MAAM,OAAO,GAAG;AACzB,YAAM,MAAMA,MAAK,QAAQ,MAAM,IAAI;AACnC,UAAI,CAAC,CAAC,OAAO,KAAK,EAAE,SAAS,GAAG,EAAG;AAEnC,YAAM,WAAWA,MAAK,SAAS,MAAM,MAAM,GAAG;AAE9C,YAAM,cAAc,aAAa,WAAW,aAAa,UACrD,iBACA,CAAC,GAAG,gBAAgB,QAAQ;AAEhC,YAAM,UAAU,UAAU,YAAY,KAAK,GAAG;AAE9C,aAAO,IAAI,KAAK;AAAA,QACd,MAAM,UAAU;AAAA,QAChB,MAAM,QAAQ,QAAQ,QAAQ,GAAG,KAAK;AAAA,QACtC,UAAU;AAAA,QACV,SAAS,mBAAmB,OAAO;AAAA,QACnC,UAAU,CAAC,OAAO,GAAG,WAAW,EAAE,OAAO,OAAO;AAAA,MAClD,CAAC;AAAA,IACH;AAAA,EACF;AACF;AASA,SAAS,mBAAmB,WAA2B;AACrD,MAAI,UAAU,UACX,QAAQ,YAAY,MAAM,EAC1B,QAAQ,WAAW,SAAS,EAC5B,QAAQ,OAAO,KAAK;AAEvB,SAAO,IAAI,OAAO,IAAI,OAAO,GAAG;AAClC;AAyEA,SAAS,UAAU,QAAgC;AACjD,QAAM,OAAsB,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,EAAE;AAEvD,aAAW,SAAS,QAAQ;AAC1B,QAAI,UAAU;AACd,eAAW,WAAW,MAAM,UAAU;AACpC,UAAI,CAAC,QAAQ,SAAS,OAAO,GAAG;AAC9B,gBAAQ,SAAS,OAAO,IAAI,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,EAAE;AAAA,MACzD;AACA,gBAAU,QAAQ,SAAS,OAAO;AAAA,IACpC;AACA,YAAQ,OAAO,KAAK,KAAK;AAAA,EAC3B;AAEA,SAAO;AACT;;;AEzVO,IAAM,UAAU;;;ACGvB,IAAM,SAAS;AAAA,EACb,OAAO;AAAA,EACP,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AACR;AAEA,IAAM,IAAI;AAUV,SAAS,eAAe,QAAgB;AACtC,MAAI,UAAU,IAAK,QAAO,EAAE;AAC5B,MAAI,UAAU,IAAK,QAAO,EAAE;AAC5B,MAAI,UAAU,IAAK,QAAO,EAAE;AAC5B,MAAI,UAAU,IAAK,QAAO,EAAE;AAC5B,SAAO,EAAE;AACX;AAEA,SAAS,QAAQ,IAAY;AAC3B,MAAI,KAAK,EAAG,QAAO,GAAG,EAAE,IAAI,OAAO,EAAE,KAAK;AAC1C,MAAI,KAAK,IAAK,QAAO,GAAG,EAAE,KAAK,GAAG,EAAE,KAAK,EAAE,KAAK;AAChD,MAAI,KAAK,IAAK,QAAO,GAAG,EAAE,MAAM,GAAG,EAAE,KAAK,EAAE,KAAK;AACjD,SAAO,GAAG,EAAE,GAAG,GAAG,EAAE,KAAK,EAAE,KAAK;AAClC;AAEA,IAAM,OAAO;AAAA,IACT,EAAE,IAAI,SAAI,EAAE,KAAK,IAAI,EAAE,IAAI,QAAQ,EAAE,KAAK,IAAI,EAAE,GAAG,IAAI,OAAO,GAAG,EAAE,KAAK;AAAA;AAGrE,IAAM,SAAS;AAAA,EACpB,OAAO;AACL,YAAQ,IAAI,IAAI;AAChB,YAAQ,IAAI,GAAG,EAAE,GAAG,yRAAmD,EAAE,KAAK,EAAE;AAChF,YAAQ,IAAI,EAAE;AAAA,EAChB;AAAA,EAEA,YAAY,QAAkF,YAAY,KAAK,IAAI,GAAG;AACpH,UAAM,EAAE,MAAM,MAAM,MAAM,SAAS,IAAI;AACvC,UAAM,UAAU,KAAK,IAAI,IAAI;AAE7B,YAAQ,IAAI,IAAI;AAChB,YAAQ,IAAI,KAAK,EAAE,KAAK,SAAI,EAAE,KAAK,IAAI,EAAE,IAAI,QAAQ,EAAE,KAAK,OAAO,OAAO,IAAI;AAC9E,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,KAAK,EAAE,IAAI,SAAS,EAAE,KAAK,SAAS,EAAE,IAAI,UAAU,IAAI,IAAI,IAAI,GAAG,EAAE,KAAK,EAAE;AACxF,YAAQ,IAAI,KAAK,EAAE,IAAI,QAAQ,EAAE,KAAK,UAAU,SAAS,gBAAgB,EAAE,SAAS,EAAE,KAAK,GAAG,IAAI,GAAG,EAAE,KAAK,EAAE;AAC9G,QAAI,SAAU,SAAQ,IAAI,KAAK,EAAE,IAAI,OAAO,EAAE,KAAK,WAAW,EAAE,GAAG,GAAG,QAAQ,GAAG,EAAE,KAAK,EAAE;AAC1F,YAAQ,IAAI,EAAE;AAAA,EAChB;AAAA,EAEA,QAAQ,QAAgBE,OAAc,QAAgB,MAAc,QAA2B,CAAC,GAAG;AACjG,UAAM,cAAc,eAAe,MAAM;AACzC,UAAM,UAAU,QAAQ,IAAI;AAE5B,QAAI,QAAQ,GAAG,EAAE,GAAG,SAAI,EAAE,KAAK;AAC/B,QAAI,MAAM,SAAS,aAAa,MAAM,SAAS,MAAO,SAAQ,GAAG,EAAE,KAAK,SAAI,EAAE,KAAK;AAAA,aAC1E,MAAM,SAAS,MAAO,SAAQ,GAAG,EAAE,IAAI,SAAI,EAAE,KAAK;AAE3D,UAAM,YAAY,GAAG,WAAW,GAAG,MAAM,GAAG,EAAE,KAAK;AACnD,YAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,KAAK,GAAG,MAAM,GAAG,EAAE,KAAK,IAAIA,KAAI,IAAI,SAAS,IAAI,EAAE,GAAG,GAAG,OAAO,GAAG,EAAE,KAAK,EAAE;AAAA,EAC1G;AAAA,EAEA,KAAK,KAAa;AAAE,YAAQ,IAAI,KAAK,EAAE,IAAI,SAAI,EAAE,KAAK,IAAI,GAAG,EAAE;AAAA,EAAG;AAAA,EAClE,QAAQ,KAAa;AAAE,YAAQ,IAAI,KAAK,EAAE,KAAK,SAAI,EAAE,KAAK,IAAI,GAAG,EAAE;AAAA,EAAG;AAAA,EACtE,KAAK,KAAa;AAAE,YAAQ,IAAI,KAAK,EAAE,MAAM,SAAI,EAAE,KAAK,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,EAAE,KAAK,EAAE;AAAA,EAAG;AAAA,EAEzF,MAAM,KAAa,MAAoB,MAAM;AAC3C,YAAQ,IAAI,KAAK,EAAE,GAAG,SAAI,EAAE,KAAK,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG,EAAE,KAAK,EAAE;AAC5D,QAAI,KAAK,OAAO;AACd,cAAQ,IAAI,EAAE;AACd,cAAQ,IAAI,GAAG,EAAE,GAAG,GAAG,IAAI,MAAM,MAAM,IAAI,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE;AAC/E,cAAQ,IAAI,EAAE;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,QAAQ,MAAc,MAAc;AAClC,YAAQ,IAAI,KAAK,EAAE,KAAK,SAAI,EAAE,KAAK,cAAc,EAAE,GAAG,GAAG,IAAI,GAAG,EAAE,KAAK,IAAI,EAAE,GAAG,IAAI,IAAI,MAAM,EAAE,KAAK,EAAE;AAAA,EACzG;AAAA,EAEA,IAAI,MAAc;AAChB,YAAQ,IAAI,KAAK,EAAE,KAAK,SAAI,EAAE,KAAK,iBAAiB,EAAE,GAAG,GAAG,IAAI,GAAG,EAAE,KAAK,EAAE;AAAA,EAC9E;AAAA,EAEA,OAAO,MAAc;AACnB,YAAQ,IAAI,KAAK,EAAE,IAAI,SAAI,EAAE,KAAK,WAAW,EAAE,GAAG,GAAG,IAAI,GAAG,EAAE,KAAK,EAAE;AAAA,EACvE;AAAA,EAEA,MAAMA,OAAc,MAAc;AAChC,UAAM,YAAY,SAAS,QAAQ,WAAM,SAAS,YAAY,WAAM;AACpE,UAAM,QAAQ,SAAS,QAAQ,EAAE,OAAO,SAAS,YAAY,EAAE,QAAQ,EAAE;AACzE,YAAQ,IAAI,KAAK,KAAK,GAAG,SAAS,GAAG,EAAE,KAAK,IAAIA,KAAI,EAAE;AAAA,EACxD;AAAA,EAEA,UAAU;AAAE,YAAQ,IAAI,GAAG,EAAE,GAAG,yRAAmD,EAAE,KAAK,EAAE;AAAA,EAAG;AAAA,EAC/F,QAAQ;AAAE,YAAQ,IAAI,EAAE;AAAA,EAAG;AAAA,EAE3B,UAAU,MAAuB;AAC/B,SAAK,MAAM,QAAQ,IAAI,qBAAqB;AAC5C,SAAK,MAAM;AACX,YAAQ,IAAI,KAAK,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE;AACtC,YAAQ,IAAI,iCAAiC,IAAI,EAAE;AACnD,YAAQ,IAAI,4CAA4C;AACxD,SAAK,MAAM;AAAA,EACb;AAAA,EAEA,MAAM,OAAyB;AAC7B,SAAK,MAAM;AACX,YAAQ,IAAI,KAAK,EAAE,KAAK,SAAI,EAAE,KAAK,kBAAkB;AACrD,SAAK,MAAM;AACX,YAAQ,IAAI,KAAK,EAAE,GAAG,cAAc,EAAE,KAAK,IAAI,EAAE,KAAK,GAAG,MAAM,IAAI,KAAK,EAAE,KAAK,EAAE;AACjF,SAAK,MAAM;AAAA,EACb;AACF;AAEA,IAAO,iBAAQ;;;AL9Gf,eAAsB,MAAM,UAAwB,CAAC,GAAG;AACtD,QAAM,cAAc,QAAQ,eAAe,QAAQ,IAAI;AACvD,QAAM,SAAS,MAAM,WAAW,WAAW;AAC3C,QAAM,WAAW,aAAa,QAAQ,WAAW;AAEjD,QAAM,SAAS,QAAQ,UAAU,SAAS;AAC1C,QAAM,YAAY,KAAK,IAAI;AAE3B,iBAAO,KAAK;AACZ,iBAAO,KAAK,4BAA4B;AACxC,iBAAO,MAAM;AAGb,WAAS,MAAM;AAEf,QAAM,SAAS,SAAS;AACxB,QAAM,SAAS,eAAe,MAAM;AAGpC,QAAM,cAAc,UAAU,QAAQ,gBAAgB;AAEtD,MAAI,YAAY,WAAW,GAAG;AAC5B,mBAAO,KAAK,yCAAyC;AACrD;AAAA,EACF;AAGA,MAAI;AACF,UAAM,eAAeC,MAAK,KAAK,QAAQ,QAAQ;AAC/C,cAAU,YAAY;AAEtB,UAAM,QAAQ,MAAM;AAAA,MAClB,aAAa;AAAA,MACb,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,QAAQ,OAAO,MAAM;AAAA,MACrB,QAAQ,QAAQ,UAAU,OAAO,MAAM;AAAA,MACvC,WAAW,QAAQ,aAAa,OAAO,MAAM;AAAA,MAC7C,KAAK;AAAA,MACL,UAAU;AAAA,MACV,aAAa;AAAA,MACb,eAAe;AAAA,IACjB,CAAC;AAED,mBAAO,QAAQ,qBAAqB;AAAA,EACtC,SAAS,KAAU;AACjB,mBAAO,MAAM,uBAAuB,GAAG;AACvC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAI;AACF,UAAM,eAAeA,MAAK,KAAK,QAAQ,QAAQ;AAC/C,cAAU,YAAY;AAEtB,UAAM,cAAc,YAAY,OAAO,OAAK;AAC1C,YAAM,UAAUC,IAAG,aAAa,GAAG,OAAO;AAC1C,YAAM,YAAY,QAAQ,MAAM,IAAI,EAAE,CAAC,GAAG,KAAK;AAC/C,aAAO,cAAc,kBAAkB,cAAc,kBAC9C,cAAc,kBAAkB,cAAc;AAAA,IACvD,CAAC;AAED,QAAI,YAAY,SAAS,GAAG;AAC1B,YAAM,QAAQ,MAAM;AAAA,QAClB,aAAa;AAAA,QACb,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,QAAQ,CAAC,QAAQ;AAAA,QACjB,QAAQ,QAAQ,UAAU,OAAO,MAAM;AAAA,QACvC,WAAW,QAAQ,aAAa,OAAO,MAAM;AAAA,QAC7C,WAAW,OAAO,MAAM;AAAA,QACxB,KAAK;AAAA,QACL,UAAU;AAAA,QACV,UAAU,CAAC,SAAS,WAAW;AAAA,QAC/B,aAAa;AAAA,QACb,eAAe;AAAA,QACf,MAAM,QAAQ,UAAU,OAAO,MAAM,SAAS,CAAC,WAAW,UAAU,IAAI,CAAC;AAAA,QACzE,YAAY;AAAA,MACd,CAAC;AAED,qBAAO,QAAQ,wBAAwB,YAAY,MAAM,cAAc;AAAA,IACzE;AAAA,EACF,SAAS,KAAU;AACjB,mBAAO,MAAM,uBAAuB,GAAG;AACvC,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,YAAY,SAAS;AAC3B,MAAIA,IAAG,WAAW,SAAS,GAAG;AAC5B,UAAM,eAAeD,MAAK,KAAK,QAAQ,QAAQ;AAC/C,cAAU,YAAY;AACtB,qBAAiB,WAAW,YAAY;AACxC,mBAAO,QAAQ,sBAAsB;AAAA,EACvC;AAGA,QAAM,WAAW;AAAA,IACf,SAAS;AAAA,IACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,QAAQ,OAAO,UAAU,IAAI,QAAM;AAAA,MACjC,MAAM,EAAE;AAAA,MACR,MAAM,EAAE,KAAK,SAAS,GAAG,IAAI,YAAY;AAAA,IAC3C,EAAE;AAAA,IACF,KAAK,OAAO,IAAI,IAAI,QAAM,EAAE,MAAM,EAAE,KAAK,EAAE;AAAA,EAC7C;AAEA,EAAAC,IAAG,cAAcD,MAAK,KAAK,QAAQ,eAAe,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAEtF,QAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,QAAM,YAAY,WAAW,MAAM;AAEnC,iBAAO,MAAM;AACb,iBAAO,QAAQ;AACf,iBAAO,MAAM;AAGb,SAAO,UAAU,QAAQ,OAAK;AAC5B,UAAM,OAAO,EAAE,KAAK,SAAS,GAAG,KAAK,EAAE,KAAK,SAAS,GAAG,IAAI,YAAY;AACxE,mBAAO,MAAM,EAAE,MAAM,IAAI;AAAA,EAC3B,CAAC;AACD,SAAO,IAAI,QAAQ,OAAK,eAAO,MAAM,EAAE,MAAM,KAAK,CAAC;AAEnD,iBAAO,MAAM;AACb,iBAAO,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9B,iBAAO,KAAK,WAAW,MAAM,KAAK,YAAY,SAAS,CAAC,GAAG;AAC3D,iBAAO,MAAM;AACf;AAMA,SAAS,iBAAiB,KAAa,MAAc;AACnD,YAAU,IAAI;AACd,QAAM,UAAUC,IAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAC3D,aAAW,SAAS,SAAS;AAC3B,UAAM,UAAUD,MAAK,KAAK,KAAK,MAAM,IAAI;AACzC,UAAM,WAAWA,MAAK,KAAK,MAAM,MAAM,IAAI;AAC3C,QAAI,MAAM,YAAY,EAAG,kBAAiB,SAAS,QAAQ;AAAA,QACtD,CAAAC,IAAG,aAAa,SAAS,QAAQ;AAAA,EACxC;AACF;AAEA,SAAS,WAAW,KAAqB;AACvC,MAAI,OAAO;AACX,MAAI,CAACA,IAAG,WAAW,GAAG,EAAG,QAAO;AAChC,QAAM,UAAUA,IAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAC3D,aAAW,SAAS,SAAS;AAC3B,UAAM,WAAWD,MAAK,KAAK,KAAK,MAAM,IAAI;AAC1C,QAAI,MAAM,YAAY,EAAG,SAAQ,WAAW,QAAQ;AAAA,QAC/C,SAAQC,IAAG,SAAS,QAAQ,EAAE;AAAA,EACrC;AACA,SAAO;AACT;;;AM9KA,MAAM,EAAE,MAAM,SAAO;AACnB,iBAAO,MAAM,gBAAgB,GAAG;AAChC,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["fs","path","fs","path","fs","path","fs","path","fs","path","fs","path","path","fs"]}
@@ -701,7 +701,7 @@ init_esm_shims();
701
701
 
702
702
  // version.ts
703
703
  init_esm_shims();
704
- var VERSION = "5.1.7";
704
+ var VERSION = "5.2.3";
705
705
 
706
706
  // logger.ts
707
707
  var colors = {
@@ -1065,6 +1065,8 @@ import { useFormStatus } from "react-dom";
1065
1065
 
1066
1066
  // helpers.ts
1067
1067
  init_esm_shims();
1068
+ import { NotFoundError as CoreNotFoundError } from "@teamvelix/velix-core";
1069
+ import { NotFoundError } from "@teamvelix/velix-core";
1068
1070
  var RedirectError = class extends Error {
1069
1071
  url;
1070
1072
  statusCode;
@@ -1076,19 +1078,12 @@ var RedirectError = class extends Error {
1076
1078
  this.statusCode = statusCode;
1077
1079
  }
1078
1080
  };
1079
- var NotFoundError = class extends Error {
1080
- type = "notFound";
1081
- constructor(message = "Page not found") {
1082
- super(message);
1083
- this.name = "NotFoundError";
1084
- }
1085
- };
1086
1081
  function redirect(url, type = "replace") {
1087
1082
  const statusCode = type === "permanent" ? 308 : 307;
1088
1083
  throw new RedirectError(url, statusCode);
1089
1084
  }
1090
1085
  function notFound(message) {
1091
- throw new NotFoundError(message);
1086
+ throw new CoreNotFoundError(message);
1092
1087
  }
1093
1088
  var cookies = {
1094
1089
  parse(cookieHeader) {
@@ -1297,7 +1292,7 @@ var ICON_TERM = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" str
1297
1292
  var ICON_LOGO = `<img src="/__velix/logo.webp" alt="Velix Logo" width="14" height="14" style="border-radius:2px; object-fit:cover;" onerror="this.style.display='none'" />`;
1298
1293
  function generateDevToolsHtml(isDev, ctx = {}) {
1299
1294
  if (!isDev) return "";
1300
- const version = ctx.version ?? "5.1.0";
1295
+ const version = ctx.version ?? VERSION;
1301
1296
  const port = ctx.port ?? 3e3;
1302
1297
  const host = ctx.host ?? "localhost";
1303
1298
  const nodeVersion = ctx.nodeVersion ?? process.version.replace("v", "");
@@ -1582,33 +1577,41 @@ function generateDevToolsHtml(isDev, ctx = {}) {
1582
1577
  if(connText) connText.style.color = ok ? '#10b981' : '#ef4444';
1583
1578
  }
1584
1579
 
1585
- var es = new EventSource('/__velix/hmr');
1580
+ var ws = new WebSocket('ws://' + window.location.host + '/__velix_hmr');
1581
+
1582
+ ws.onopen = function(){ setConn(true); };
1586
1583
 
1587
- es.onopen = function(){ setConn(true); };
1584
+ ws.onmessage = function(e){
1585
+ var data;
1586
+ try {
1587
+ data = JSON.parse(e.data);
1588
+ } catch(err) { return; }
1588
1589
 
1589
- es.onmessage = function(e){
1590
- var data = e.data;
1591
- if(data === 'reload'){
1590
+ if(data.type === 'full-reload'){
1592
1591
  setStatus('navigating');
1593
1592
  setTimeout(function(){ location.reload(); }, 120);
1594
- } else if(data === 'building'){
1593
+ } else if(data.type === 'compile-start'){
1595
1594
  setStatus('compiling');
1596
- } else if(data === 'built'){
1595
+ } else if(data.type === 'compile-done'){
1597
1596
  setStatus('idle');
1598
- } else if(data.startsWith('rendering:')){
1599
- setStatus('rendering');
1600
- setTimeout(function(){ setStatus('idle'); }, 900);
1601
- } else if(data.startsWith('error:')){
1597
+ var btel = document.getElementById('__vdt-build-time');
1598
+ if(btel) btel.textContent = data.duration + 'ms';
1599
+ } else if(data.type === 'compile-error'){
1602
1600
  setStatus('error');
1603
1601
  }
1604
1602
  };
1605
1603
 
1606
- es.onerror = function(){
1607
- if(es.readyState === 2){
1604
+ ws.onerror = function(){
1605
+ if(ws.readyState === 2 || ws.readyState === 3){
1608
1606
  setStatus('error');
1609
1607
  setConn(false);
1610
1608
  }
1611
1609
  };
1610
+
1611
+ ws.onclose = function(){
1612
+ setStatus('error');
1613
+ setConn(false);
1614
+ };
1612
1615
 
1613
1616
  setStatus('idle');
1614
1617
  })();
@@ -2260,13 +2263,13 @@ async function createServer(options = {}) {
2260
2263
  }
2261
2264
  }
2262
2265
  });
2263
- const __hmrClients = /* @__PURE__ */ new Set();
2264
- server.__hmrClients = __hmrClients;
2265
- server.broadcastHMR = (msg) => {
2266
- __hmrClients.forEach((c2) => c2.write(`data: ${msg}
2267
-
2268
- `));
2269
- };
2266
+ if (isDev) {
2267
+ const { createHMRServer } = await import("@teamvelix/velix-core");
2268
+ const hmr = createHMRServer(server, projectRoot);
2269
+ server.broadcastHMR = (msg) => {
2270
+ hmr.broadcast(msg);
2271
+ };
2272
+ }
2270
2273
  const port = config.server.port;
2271
2274
  const host = config.server.host;
2272
2275
  server.listen(port, host, () => {
@@ -2477,8 +2480,53 @@ async function handlePageRoute(route, routes, req, res, url, config, isDev, proj
2477
2480
  ${config.favicon ? `<link rel="icon" href="${config.favicon}">` : ""}
2478
2481
  ${config.styles.map((s) => `<link rel="stylesheet" href="${s}">`).join("\n ")}
2479
2482
  `;
2483
+ const { resolveErrorBoundary, getErrorBoundaryType } = await import("@teamvelix/velix-core");
2484
+ const { VelixErrorBoundary, VelixDefaultErrorPage } = await import("@teamvelix/velix-react");
2485
+ const errorBoundary = resolveErrorBoundary(route.filePath, appDir, "error");
2486
+ const notFoundBoundary = resolveErrorBoundary(route.filePath, appDir, "not-found");
2487
+ let ErrorComponent = null;
2488
+ let NotFoundComponent = null;
2489
+ if (errorBoundary) {
2490
+ try {
2491
+ const mod2 = await import(`${pathToFileURL3(errorBoundary.filePath).href}?t=${Date.now()}`);
2492
+ ErrorComponent = mod2.default;
2493
+ } catch (e) {
2494
+ }
2495
+ }
2496
+ if (notFoundBoundary) {
2497
+ try {
2498
+ const mod2 = await import(`${pathToFileURL3(notFoundBoundary.filePath).href}?t=${Date.now()}`);
2499
+ NotFoundComponent = mod2.default;
2500
+ } catch (e) {
2501
+ }
2502
+ }
2480
2503
  const searchParams = Object.fromEntries(url.searchParams.entries());
2481
- let pageElement = await renderComponentAsync(PageComponent, { params: route.params, searchParams, query: searchParams });
2504
+ let pageElement;
2505
+ try {
2506
+ pageElement = await renderComponentAsync(PageComponent, { params: route.params, searchParams, query: searchParams });
2507
+ } catch (ssrError) {
2508
+ const err = ssrError;
2509
+ const errorType = getErrorBoundaryType(err);
2510
+ res.statusCode = err.status || (errorType === "not-found" ? 404 : 500);
2511
+ if (errorType === "not-found" && NotFoundComponent) {
2512
+ pageElement = React2.createElement(NotFoundComponent);
2513
+ } else if (ErrorComponent) {
2514
+ pageElement = React2.createElement(ErrorComponent, { error: err, reset: () => {
2515
+ } });
2516
+ } else {
2517
+ pageElement = React2.createElement(VelixDefaultErrorPage, { error: err, reset: () => {
2518
+ } });
2519
+ }
2520
+ }
2521
+ pageElement = React2.createElement(
2522
+ VelixErrorBoundary,
2523
+ {
2524
+ errorComponent: ErrorComponent,
2525
+ notFoundComponent: NotFoundComponent,
2526
+ routePath: route.filePath
2527
+ },
2528
+ pageElement
2529
+ );
2482
2530
  let layoutElement = pageElement;
2483
2531
  for (let i = layoutModules.length - 1; i >= 0; i--) {
2484
2532
  const layoutMod = layoutModules[i];
@@ -2740,7 +2788,7 @@ async function startDev() {
2740
2788
  const relative = path8.relative(projectRoot, filePath);
2741
2789
  logger_default.hmr(relative);
2742
2790
  if (server.broadcastHMR) {
2743
- server.broadcastHMR("reload");
2791
+ server.broadcastHMR({ type: "full-reload" });
2744
2792
  }
2745
2793
  });
2746
2794
  watcher.on("add", (filePath) => {