loly 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +374 -0
- package/bin/loly.js +3015 -0
- package/dist/bootstrap-DgWagZ79.d.ts +16 -0
- package/dist/client.d.ts +101 -0
- package/dist/client.js +727 -0
- package/dist/client.js.map +1 -0
- package/dist/components.d.ts +39 -0
- package/dist/components.js +147 -0
- package/dist/components.js.map +1 -0
- package/dist/index.d.ts +458 -0
- package/dist/index.js +3826 -0
- package/dist/index.js.map +1 -0
- package/package.json +108 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/router/scanner.ts","../src/constants/routes.ts","../src/constants/directories.ts","../src/constants/files.ts","../src/constants/http.ts","../src/constants/server.ts","../src/constants/node-builtins.ts","../src/constants/errors.ts","../src/utils/path.ts","../src/utils/module-loader.ts","../src/router/matcher.ts","../src/server/dev-server.ts","../src/utils/route-component-factory.ts","../src/server/rendering/strategies.ts","../src/server/async-registry.ts","../src/context.ts","../src/utils/html.ts","../src/utils/assets.ts","../src/utils/errors.ts","../src/utils/env.ts","../src/server/ssr.ts","../src/server/base-server.ts","../src/utils/express-setup.ts","../src/server/handlers/image.ts","../src/server/utils/image-optimizer.ts","../src/server/utils/image-validation.ts","../src/server/utils/image-cache.ts","../src/router/api-matcher.ts","../src/utils/api-route-loader.ts","../src/server/handlers/api-route.ts","../src/server/handlers/async-handler.ts","../src/server/prod-server.ts","../src/client/router.ts","../src/utils/route-matcher.ts","../src/client/bootstrap.tsx","../src/build/index.ts","../src/build/manifest.ts","../src/build/client.ts","../src/build/server-only.ts","../src/build/server.ts","../src/build/css-processor.ts","../src/client/components/Image/index.tsx"],"sourcesContent":["import { glob } from \"glob\";\r\nimport { relative, dirname, sep } from \"path\";\r\nimport type { RouteFile, RouteSegment, RouteConfig } from \"./types\";\r\nimport { ROUTE_FILE_NAMES } from \"../constants\";\r\nimport { normalizeUrlPath } from \"../utils/path\";\r\nimport { loadModule } from \"../utils/module-loader\";\r\n\r\n/**\r\n * Parse a route segment and determine its type\r\n */\r\nfunction parseSegment(segment: string): RouteSegment {\r\n // Optional groups: (group)\r\n // Keep the original segment with parentheses for file path construction\r\n if (segment.startsWith(\"(\") && segment.endsWith(\")\")) {\r\n return {\r\n segment: segment, // Keep original with parentheses: (admin)\r\n isDynamic: false,\r\n isCatchAll: false,\r\n isOptional: true,\r\n };\r\n }\r\n\r\n // Catch-all: [...slug]\r\n if (segment.startsWith(\"[...\") && segment.endsWith(\"]\")) {\r\n const paramName = segment.slice(4, -1);\r\n return {\r\n segment,\r\n isDynamic: true,\r\n isCatchAll: true,\r\n isOptional: false,\r\n paramName,\r\n };\r\n }\r\n\r\n // Optional catch-all: [[...slug]]\r\n if (segment.startsWith(\"[[...\") && segment.endsWith(\"]]\")) {\r\n const paramName = segment.slice(5, -2);\r\n return {\r\n segment,\r\n isDynamic: true,\r\n isCatchAll: true,\r\n isOptional: true,\r\n paramName,\r\n };\r\n }\r\n\r\n // Dynamic: [id]\r\n if (segment.startsWith(\"[\") && segment.endsWith(\"]\")) {\r\n const paramName = segment.slice(1, -1);\r\n return {\r\n segment,\r\n isDynamic: true,\r\n isCatchAll: false,\r\n isOptional: false,\r\n paramName,\r\n };\r\n }\r\n\r\n // Static segment\r\n return {\r\n segment,\r\n isDynamic: false,\r\n isCatchAll: false,\r\n isOptional: false,\r\n };\r\n}\r\n\r\n/**\r\n * Convert segments to a URL path (for loly-jsx router format)\r\n */\r\nfunction segmentsToUrlPath(segments: RouteSegment[]): string {\r\n const parts: string[] = [];\r\n\r\n for (const seg of segments) {\r\n if (seg.isOptional) {\r\n // Optional groups don't appear in URL\r\n continue;\r\n }\r\n\r\n if (seg.isCatchAll) {\r\n parts.push(`*${seg.paramName || \"slug\"}`);\r\n } else if (seg.isDynamic) {\r\n parts.push(`:${seg.paramName || \"param\"}`);\r\n } else {\r\n parts.push(seg.segment);\r\n }\r\n }\r\n\r\n const path = \"/\" + parts.join(\"/\");\r\n return normalizeUrlPath(path);\r\n}\r\n\r\n/**\r\n * Valid HTTP methods for API routes\r\n */\r\nconst HTTP_METHODS = [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\", \"HEAD\", \"OPTIONS\"];\r\n\r\n/**\r\n * Analyze an API route file to detect exported HTTP method handlers\r\n */\r\nasync function analyzeApiRoute(filePath: string): Promise<string[]> {\r\n try {\r\n const module = await loadModule(filePath);\r\n const exports = Object.keys(module);\r\n const httpMethods: string[] = [];\r\n\r\n for (const exportName of exports) {\r\n const upperExport = exportName.toUpperCase();\r\n if (HTTP_METHODS.includes(upperExport) && typeof module[exportName] === \"function\") {\r\n httpMethods.push(upperExport);\r\n }\r\n }\r\n\r\n return httpMethods;\r\n } catch (error) {\r\n // If module can't be loaded, return empty array (might be a build issue)\r\n console.warn(`[loly-core] Failed to analyze API route ${filePath}:`, error);\r\n return [];\r\n }\r\n}\r\n\r\n/**\r\n * Scan src/app/ directory and generate route configuration\r\n */\r\nexport async function scanRoutes(appDir: string): Promise<RouteConfig> {\r\n const routes: RouteFile[] = [];\r\n const routeMap = new Map<string, RouteFile>();\r\n const apiRouteMap = new Map<string, RouteFile>();\r\n\r\n // Find all route files\r\n const patterns = ROUTE_FILE_NAMES.map((file) => `**/${file}`);\r\n const files = await glob(patterns, { cwd: appDir, absolute: true });\r\n\r\n let rootLayout: RouteFile | undefined;\r\n\r\n for (const file of files) {\r\n const absolutePath = file;\r\n const relativePath = relative(appDir, absolutePath);\r\n const dir = dirname(relativePath);\r\n const fileName = file.split(sep).pop() || \"\";\r\n\r\n // Determine file type\r\n let type: \"page\" | \"layout\" | \"route\";\r\n if (fileName.startsWith(\"page.\")) {\r\n type = \"page\";\r\n } else if (fileName.startsWith(\"layout.\")) {\r\n type = \"layout\";\r\n } else if (fileName.startsWith(\"route.\")) {\r\n type = \"route\";\r\n } else {\r\n continue;\r\n }\r\n\r\n // Parse route segments\r\n const pathSegments = dir === \".\" ? [] : dir.split(sep).filter(Boolean);\r\n const segments: RouteSegment[] = pathSegments.map(parseSegment);\r\n\r\n const isRootLayout = type === \"layout\" && dir === \".\";\r\n\r\n // Generate URL path\r\n let urlPath = \"\";\r\n let isApiRoute = false;\r\n let httpMethods: string[] | undefined = undefined;\r\n\r\n if (type === \"page\") {\r\n urlPath = segmentsToUrlPath(segments);\r\n } else if (type === \"route\") {\r\n // Analyze API route to detect HTTP methods\r\n httpMethods = await analyzeApiRoute(absolutePath);\r\n if (httpMethods.length > 0) {\r\n isApiRoute = true;\r\n urlPath = segmentsToUrlPath(segments);\r\n }\r\n }\r\n\r\n const routeFile: RouteFile = {\r\n filePath: absolutePath,\r\n segments,\r\n type,\r\n isRootLayout,\r\n urlPath,\r\n isApiRoute: isApiRoute || undefined,\r\n httpMethods,\r\n };\r\n\r\n routes.push(routeFile);\r\n\r\n if (isRootLayout) {\r\n rootLayout = routeFile;\r\n }\r\n\r\n if (type === \"page\") {\r\n routeMap.set(urlPath, routeFile);\r\n } else if (isApiRoute && urlPath) {\r\n apiRouteMap.set(urlPath, routeFile);\r\n }\r\n }\r\n\r\n return {\r\n routes,\r\n rootLayout,\r\n routeMap,\r\n apiRouteMap,\r\n };\r\n}\r\n\r\n","/**\r\n * Route file names that are recognized by the framework\r\n */\r\nexport const ROUTE_FILE_NAMES = [\r\n \"page.tsx\",\r\n \"page.ts\",\r\n \"layout.tsx\",\r\n \"layout.ts\",\r\n \"route.ts\",\r\n \"route.tsx\",\r\n] as const;\r\n\r\n/**\r\n * Valid route types\r\n */\r\nexport const ROUTE_TYPES = [\"page\", \"layout\", \"route\"] as const;\r\n\r\nexport type RouteType = (typeof ROUTE_TYPES)[number];\r\n\r\n","/**\r\n * Directory names used throughout the framework\r\n */\r\nexport const DIRECTORIES = {\r\n SRC: \"src\",\r\n APP: \"app\",\r\n DIST: \"dist\",\r\n CLIENT: \"client\",\r\n SERVER: \"server\",\r\n PUBLIC: \"public\",\r\n LOLY: \".loly\",\r\n} as const;\r\n\r\n","/**\r\n * File names used throughout the framework\r\n */\r\nexport const FILE_NAMES = {\r\n MANIFEST: \"manifest.json\",\r\n BOOTSTRAP: \"bootstrap.ts\",\r\n GLOBALS_CSS: \"globals.css\",\r\n ROUTES_MANIFEST: \"routes-manifest.json\",\r\n} as const;\r\n\r\n","/**\r\n * HTTP status codes\r\n */\r\nexport const HTTP_STATUS = {\r\n OK: 200,\r\n BAD_REQUEST: 400,\r\n NOT_FOUND: 404,\r\n METHOD_NOT_ALLOWED: 405,\r\n REQUEST_TIMEOUT: 408,\r\n INTERNAL_ERROR: 500,\r\n} as const;\r\n\r\n/**\r\n * HTTP headers\r\n */\r\nexport const HTTP_HEADERS = {\r\n CONTENT_TYPE_JSON: \"application/json\",\r\n CONTENT_TYPE_HTML: \"text/html; charset=utf-8\",\r\n} as const;\r\n\r\n","/**\r\n * Server-related constants\r\n */\r\nexport const SERVER = {\r\n DEFAULT_PORT: 3000,\r\n RSC_ENDPOINT: \"/__loly/rsc\",\r\n IMAGE_ENDPOINT: \"/_loly/image\",\r\n ASYNC_ENDPOINT: \"/__loly/async\",\r\n APP_CONTAINER_ID: \"app\",\r\n} as const;\r\n\r\n","/**\r\n * Node.js built-in modules that should be externalized in builds\r\n */\r\nexport const NODE_BUILTINS = [\r\n \"fs\",\r\n \"path\",\r\n \"url\",\r\n \"util\",\r\n \"stream\",\r\n \"events\",\r\n \"crypto\",\r\n \"http\",\r\n \"https\",\r\n \"os\",\r\n \"querystring\",\r\n \"buffer\",\r\n \"constants\",\r\n \"child_process\",\r\n \"module\",\r\n \"fs/promises\",\r\n \"worker_threads\",\r\n \"zlib\",\r\n \"inspector\",\r\n \"perf_hooks\",\r\n] as const;\r\n\r\n","/**\r\n * Error messages used throughout the framework\r\n */\r\nexport const ERROR_MESSAGES = {\r\n CONTEXT_NOT_INITIALIZED:\r\n \"[loly-core] Framework context not initialized. Call setContext() first.\",\r\n APP_DIR_NOT_FOUND: (dir: string) =>\r\n `[loly-core] src/app/ directory not found in ${dir}. Please ensure your project has a src/app/ directory.`,\r\n ROUTE_NOT_FOUND: (pathname: string) => `Route not found: ${pathname}`,\r\n PAGE_COMPONENT_NOT_FOUND: (path: string) =>\r\n `[loly-core] Page component not found in ${path}`,\r\n PAGE_COMPONENT_MUST_BE_FUNCTION:\r\n \"[loly-core] Page component must be a function\",\r\n COMPONENT_NOT_FOUND: (route: string) =>\r\n `Component not found for route: ${route}`,\r\n APP_CONTAINER_NOT_FOUND: \"[loly-core] App container not found (#app)\",\r\n CLIENT_BUILD_DIR_NOT_FOUND: (dir: string) =>\r\n `[loly-core] Client build directory not found: ${dir}. Run 'loly build' first or the client scripts won't load.`,\r\n ROUTES_MANIFEST_NOT_FOUND: (path: string) =>\r\n `[loly-core] Routes manifest not found: ${path}. Run 'loly build' first.`,\r\n DIRECTORY_NOT_FOUND: (dir: string) =>\r\n `[loly-core] Directory not found: ${dir}`,\r\n CLIENT_BUILD_FAILED: \"Client build failed\",\r\n SERVER_BUILD_FAILED: \"Server build failed\",\r\n FAILED_TO_LOAD_MODULE: (path: string) =>\r\n `[loly-core] Failed to load module: ${path}`,\r\n FAILED_TO_LOAD_ROUTE_COMPONENT: (path: string) =>\r\n `[bootstrap] Failed to load component for route ${path}`,\r\n FAILED_TO_LOAD_NESTED_LAYOUT: (path: string) =>\r\n `[loly-core] Failed to load nested layout at ${path}`,\r\n FAILED_TO_READ_CLIENT_MANIFEST: \"[loly-core] Failed to read client manifest:\",\r\n FAILED_TO_PARSE_ISLAND_DATA: \"[loly-core] Failed to parse island data:\",\r\n FATAL_BOOTSTRAP_ERROR: \"[bootstrap] Fatal error during bootstrap:\",\r\n UNEXPECTED_ERROR: \"[loly-core] Unexpected error:\",\r\n ERROR_STARTING_DEV_SERVER: \"[loly-core] Error starting dev server:\",\r\n ERROR_STARTING_PROD_SERVER: \"[loly-core] Error starting production server:\",\r\n ERROR_BUILDING_PROJECT: \"[loly-core] Error building project:\",\r\n ERROR_HANDLING_REQUEST: \"[loly-core] Error handling request:\",\r\n ERROR_RENDERING_PAGE: \"[loly-core] Error rendering page:\",\r\n RSC_ENDPOINT_ERROR: \"[loly-core] RSC endpoint error:\",\r\n} as const;\r\n\r\n","import { resolve } from \"path\";\r\n\r\n/**\r\n * Normalize a path by removing trailing slashes and handling root\r\n */\r\nexport function normalizePath(path: string): string {\r\n if (path === \"/\") return \"/\";\r\n return path.replace(/\\/$/, \"\") || \"/\";\r\n}\r\n\r\n/**\r\n * Normalize a URL pathname (remove trailing slashes, handle root)\r\n */\r\nexport function normalizeUrlPath(pathname: string): string {\r\n return normalizePath(pathname);\r\n}\r\n\r\n/**\r\n * Convert a file path to a file:// URL for dynamic imports\r\n */\r\nexport function resolveModulePath(path: string): string {\r\n const absolutePath = resolve(path);\r\n const normalizedPath = absolutePath.replace(/\\\\/g, \"/\");\r\n \r\n if (normalizedPath.startsWith(\"/\")) {\r\n return `file://${normalizedPath}`;\r\n }\r\n return `file:///${normalizedPath}`;\r\n}\r\n\r\n/**\r\n * Get relative path from one directory to another\r\n */\r\nexport function getRelativePath(from: string, to: string): string {\r\n const { relative } = require(\"path\");\r\n return relative(from, to);\r\n}\r\n\r\n","import { resolve } from \"path\";\r\nimport { existsSync } from \"fs\";\r\nimport { ERROR_MESSAGES } from \"../constants/errors\";\r\n\r\n// Register tsx loader for TypeScript files\r\nlet tsxRegistered = false;\r\nlet tsxRegistrationPromise: Promise<void> | null = null;\r\n\r\n/**\r\n * Ensure tsx is registered for TypeScript file loading\r\n */\r\nexport async function ensureTsxRegistered(): Promise<void> {\r\n if (tsxRegistered) {\r\n return;\r\n }\r\n\r\n if (tsxRegistrationPromise) {\r\n await tsxRegistrationPromise;\r\n return;\r\n }\r\n\r\n tsxRegistrationPromise = (async () => {\r\n try {\r\n // @ts-ignore - tsx/esm may not have types\r\n await import(\"tsx/esm\");\r\n tsxRegistered = true;\r\n } catch (error) {\r\n console.warn(\r\n \"[loly-core] tsx not available, TypeScript files won't load in development\"\r\n );\r\n tsxRegistered = true;\r\n }\r\n })();\r\n\r\n await tsxRegistrationPromise;\r\n}\r\n\r\n/**\r\n * Convert a file path to a file:// URL for dynamic imports\r\n */\r\nexport function resolveModuleUrl(path: string): string {\r\n if (path.startsWith(\"file://\")) {\r\n return path;\r\n }\r\n\r\n const absolutePath = resolve(path);\r\n const normalizedPath = absolutePath.replace(/\\\\/g, \"/\");\r\n\r\n if (normalizedPath.startsWith(\"/\")) {\r\n return `file://${normalizedPath}`;\r\n }\r\n return `file:///${normalizedPath}`;\r\n}\r\n\r\n/**\r\n * Load a module dynamically\r\n * Prefers compiled server files in production, falls back to source files\r\n */\r\nexport async function loadModule(\r\n filePath: string,\r\n compiledPath?: string\r\n): Promise<any> {\r\n // Try compiled path first if provided and exists\r\n let pathToLoad = filePath;\r\n if (compiledPath && existsSync(compiledPath)) {\r\n pathToLoad = compiledPath;\r\n }\r\n\r\n try {\r\n // Only use tsx for source TypeScript files, not compiled JS\r\n if (pathToLoad.endsWith(\".ts\") || pathToLoad.endsWith(\".tsx\")) {\r\n await ensureTsxRegistered();\r\n }\r\n\r\n const fileUrl = resolveModuleUrl(pathToLoad);\r\n const module = await import(fileUrl);\r\n return module;\r\n } catch (error) {\r\n console.error(ERROR_MESSAGES.FAILED_TO_LOAD_MODULE(pathToLoad), error);\r\n throw error;\r\n }\r\n}\r\n\r\n","import type { RouteConfig, RouteFile } from \"./types\";\r\nimport { normalizeUrlPath } from \"../utils/path\";\r\n\r\n/**\r\n * Match a URL pathname to a route\r\n */\r\nexport function matchRoute(\r\n pathname: string,\r\n config: RouteConfig,\r\n loadComponent: (route: RouteFile) => Promise<any>\r\n): { route: RouteFile; params: Record<string, string> } | null {\r\n // Normalize pathname\r\n const normalized = normalizeUrlPath(pathname);\r\n\r\n // Try exact match first\r\n if (config.routeMap.has(normalized)) {\r\n const route = config.routeMap.get(normalized)!;\r\n return { route, params: {} };\r\n }\r\n\r\n // Try pattern matching\r\n for (const route of config.routes) {\r\n if (route.type !== \"page\") continue;\r\n\r\n const match = matchRoutePattern(normalized, route);\r\n if (match) {\r\n return { route, params: match.params };\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Match route pattern and extract params\r\n */\r\nfunction matchRoutePattern(\r\n pathname: string,\r\n route: RouteFile\r\n): { params: Record<string, string> } | null {\r\n const pathSegments = pathname === \"/\" ? [\"\"] : pathname.split(\"/\").filter(Boolean);\r\n const routeSegments = route.segments.filter((s) => !s.isOptional);\r\n\r\n if (routeSegments.length === 0 && pathSegments.length === 1 && pathSegments[0] === \"\") {\r\n return { params: {} }; // Root route\r\n }\r\n\r\n const params: Record<string, string> = {};\r\n let pathIdx = 0;\r\n let routeIdx = 0;\r\n\r\n while (pathIdx < pathSegments.length && routeIdx < routeSegments.length) {\r\n const routeSeg = routeSegments[routeIdx];\r\n const pathSeg = pathSegments[pathIdx];\r\n\r\n if (routeSeg.isCatchAll) {\r\n // Catch-all consumes everything remaining\r\n const remaining = pathSegments.slice(pathIdx);\r\n if (routeSeg.paramName) {\r\n params[routeSeg.paramName] = remaining.join(\"/\");\r\n }\r\n return { params };\r\n }\r\n\r\n if (routeSeg.isDynamic) {\r\n // Dynamic segment matches any value\r\n if (routeSeg.paramName) {\r\n params[routeSeg.paramName] = decodeURIComponent(pathSeg);\r\n }\r\n pathIdx++;\r\n routeIdx++;\r\n continue;\r\n }\r\n\r\n if (routeSeg.segment === pathSeg) {\r\n // Exact match\r\n pathIdx++;\r\n routeIdx++;\r\n continue;\r\n }\r\n\r\n return null;\r\n }\r\n\r\n if (pathIdx === pathSegments.length && routeIdx === routeSegments.length) {\r\n return { params };\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Extract params from pathname for a matched route\r\n */\r\nexport function extractParams(pathname: string, route: RouteFile): Record<string, string> {\r\n const match = matchRoutePattern(pathname, route);\r\n return match?.params || {};\r\n}\r\n\r\n","import { join } from \"path\";\r\nimport { existsSync } from \"fs\";\r\nimport chokidar from \"chokidar\";\r\nimport { scanRoutes } from \"../router/scanner\";\r\nimport type { RouteConfig } from \"../router/types\";\r\nimport { renderPageStream, renderPageContent } from \"./ssr\";\r\nimport {\r\n setContext,\r\n getAppDirPath,\r\n getAppDir,\r\n setRouteConfig,\r\n} from \"../context\";\r\nimport { BaseServer } from \"./base-server\";\r\nimport { SERVER, ERROR_MESSAGES, DIRECTORIES } from \"../constants\";\r\nimport type { RSCHandler, SSRHandler } from \"../utils/express-setup\";\r\n\r\nexport interface DevServerOptions {\r\n projectDir: string;\r\n port?: number;\r\n}\r\n\r\nlet routeConfig: RouteConfig | null = null;\r\nlet routeConfigPromise: Promise<RouteConfig> | null = null;\r\n\r\n/**\r\n * Reload route configuration\r\n */\r\nasync function reloadRoutes(appDir: string): Promise<RouteConfig> {\r\n const config = await scanRoutes(appDir);\r\n routeConfig = config;\r\n return config;\r\n}\r\n\r\n/**\r\n * Get route configuration (with cache)\r\n */\r\nasync function getRouteConfig(appDir: string): Promise<RouteConfig> {\r\n if (routeConfig) {\r\n return routeConfig;\r\n }\r\n if (routeConfigPromise) {\r\n return routeConfigPromise;\r\n }\r\n routeConfigPromise = reloadRoutes(appDir);\r\n return routeConfigPromise;\r\n}\r\n\r\n/**\r\n * Development server class\r\n * Extends BaseServer with hot reload capabilities\r\n */\r\nexport class DevServer extends BaseServer {\r\n private projectDir: string;\r\n private watcher: chokidar.FSWatcher | null = null;\r\n\r\n constructor(options: DevServerOptions) {\r\n super(options.port);\r\n this.projectDir = options.projectDir;\r\n }\r\n\r\n /**\r\n * Initialize server context and load routes\r\n */\r\n async initialize(): Promise<void> {\r\n const appDir = getAppDirPath(this.projectDir);\r\n const srcDir = join(this.projectDir, DIRECTORIES.SRC);\r\n const outDir = join(this.projectDir, DIRECTORIES.LOLY, DIRECTORIES.DIST);\r\n\r\n if (!existsSync(appDir)) {\r\n throw new Error(ERROR_MESSAGES.APP_DIR_NOT_FOUND(this.projectDir));\r\n }\r\n\r\n // Initialize context\r\n setContext({\r\n projectDir: this.projectDir,\r\n appDir,\r\n srcDir,\r\n outDir,\r\n buildMode: \"development\",\r\n isDev: true,\r\n serverPort: this.port,\r\n });\r\n\r\n // Load initial routes\r\n const initialConfig = await reloadRoutes(getAppDir());\r\n setRouteConfig(initialConfig);\r\n }\r\n\r\n /**\r\n * Create RSC handler\r\n */\r\n protected createRSCHandler(): RSCHandler {\r\n return async (pathname, searchParams) => {\r\n const config = await getRouteConfig(getAppDir());\r\n const context = {\r\n pathname,\r\n searchParams,\r\n params: {} as Record<string, string>,\r\n };\r\n\r\n const result = await renderPageContent(context, config, getAppDir());\r\n return {\r\n ...result,\r\n params: context.params,\r\n };\r\n };\r\n }\r\n\r\n /**\r\n * Create SSR handler\r\n */\r\n protected createSSRHandler(): SSRHandler {\r\n return async (pathname, searchParams) => {\r\n const config = await getRouteConfig(getAppDir());\r\n const context = {\r\n pathname,\r\n searchParams,\r\n params: {} as Record<string, string>,\r\n };\r\n return await renderPageStream(context, config, getAppDir());\r\n };\r\n }\r\n\r\n /**\r\n * Load route configuration\r\n */\r\n protected async loadRouteConfig(): Promise<RouteConfig> {\r\n return await getRouteConfig(getAppDir());\r\n }\r\n\r\n /**\r\n * Setup hot reload watcher\r\n */\r\n private setupHotReload(): void {\r\n this.watcher = chokidar.watch(getAppDir(), {\r\n ignored: /node_modules/,\r\n persistent: true,\r\n });\r\n\r\n const reloadHandler = async () => {\r\n routeConfig = null;\r\n routeConfigPromise = null;\r\n await reloadRoutes(getAppDir());\r\n };\r\n\r\n this.watcher.on(\"change\", reloadHandler);\r\n this.watcher.on(\"add\", reloadHandler);\r\n this.watcher.on(\"unlink\", reloadHandler);\r\n }\r\n\r\n /**\r\n * Start the development server with hot reload\r\n */\r\n async start(): Promise<void> {\r\n await this.initialize();\r\n await this.setup();\r\n this.setupHotReload();\r\n\r\n this.getApp().listen(this.port, () => {\r\n console.log(\r\n `[loly-core] Dev server running at http://localhost:${this.port}`\r\n );\r\n });\r\n }\r\n\r\n /**\r\n * Stop the server and cleanup\r\n */\r\n async stop(): Promise<void> {\r\n if (this.watcher) {\r\n await this.watcher.close();\r\n this.watcher = null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Convenience function to start development server\r\n * Maintains backward compatibility\r\n */\r\nexport async function startDevServer(\r\n options: DevServerOptions\r\n): Promise<void> {\r\n const server = new DevServer(options);\r\n await server.start();\r\n}\r\n\r\n","import { resolve, join } from \"path\";\r\nimport { existsSync } from \"fs\";\r\nimport type { RouteFile, RouteConfig } from \"../router/types\";\r\nimport type { RouteConfigWithManifest, ManifestRouteEntry } from \"../router/manifest-types\";\r\nimport { loadModule } from \"./module-loader\";\r\n\r\n/**\r\n * Factory for loading route and layout components\r\n * Centralizes component loading logic with caching support\r\n */\r\nexport class RouteComponentFactory {\r\n private componentCache = new Map<string, any>();\r\n private layoutCache = new Map<string, any[]>();\r\n\r\n /**\r\n * Load a route component\r\n * @param route - Route file information\r\n * @param compiledPath - Optional compiled path for production\r\n * @returns The loaded component module\r\n */\r\n async loadRouteComponent(\r\n route: RouteFile,\r\n compiledPath?: string\r\n ): Promise<any> {\r\n const cacheKey = compiledPath || route.filePath;\r\n \r\n if (this.componentCache.has(cacheKey)) {\r\n return this.componentCache.get(cacheKey);\r\n }\r\n\r\n const sourcePath = resolve(route.filePath);\r\n const module = await loadModule(sourcePath, compiledPath);\r\n const component = module.default;\r\n\r\n if (!component) {\r\n throw new Error(\r\n `[loly-core] Component not found in ${route.filePath}`\r\n );\r\n }\r\n\r\n this.componentCache.set(cacheKey, component);\r\n return component;\r\n }\r\n\r\n /**\r\n * Load a layout component\r\n * @param layout - Layout route file information\r\n * @param compiledPath - Optional compiled path for production\r\n * @returns The loaded layout component module\r\n */\r\n async loadLayoutComponent(\r\n layout: RouteFile,\r\n compiledPath?: string\r\n ): Promise<any> {\r\n const cacheKey = compiledPath || layout.filePath;\r\n \r\n if (this.layoutCache.has(cacheKey)) {\r\n const cached = this.layoutCache.get(cacheKey);\r\n return cached?.[0]; // Return first layout from cache\r\n }\r\n\r\n const sourcePath = resolve(layout.filePath);\r\n const module = await loadModule(sourcePath, compiledPath);\r\n const layoutComponent = module.default;\r\n\r\n if (!layoutComponent) {\r\n throw new Error(\r\n `[loly-core] Layout component not found in ${layout.filePath}`\r\n );\r\n }\r\n\r\n this.layoutCache.set(cacheKey, [layoutComponent]);\r\n return layoutComponent;\r\n }\r\n\r\n /**\r\n * Load all layouts from root to route\r\n * @param route - Target route file\r\n * @param config - Route configuration\r\n * @param appDir - Application directory\r\n * @param manifestRoute - Optional manifest route data\r\n * @returns Array of layout components in order (root to route)\r\n */\r\n async loadLayouts(\r\n route: RouteFile,\r\n config: RouteConfig,\r\n appDir: string,\r\n manifestRoute?: ManifestRouteEntry\r\n ): Promise<Array<(props: { children: any; params: Record<string, string> }) => any>> {\r\n const layouts: Array<(props: { children: any; params: Record<string, string> }) => any> = [];\r\n const configWithManifest = config as RouteConfig & RouteConfigWithManifest;\r\n const routesManifest = configWithManifest.routesManifest;\r\n\r\n // Load root layout if exists\r\n if (config.rootLayout) {\r\n const rootLayoutManifest = configWithManifest.rootLayoutManifest;\r\n const layoutSourcePath = resolve(config.rootLayout.filePath);\r\n const layoutCompiledPath = rootLayoutManifest?.serverPath\r\n ? resolve(rootLayoutManifest.serverPath)\r\n : undefined;\r\n\r\n const rootLayout = await this.loadLayoutComponent(\r\n config.rootLayout,\r\n layoutCompiledPath\r\n );\r\n layouts.push(rootLayout);\r\n }\r\n\r\n // Load nested layouts based on route segments\r\n // IMPORTANT: Use all segments including optional ones (route groups)\r\n // Route groups like (admin) should be considered when finding layouts\r\n const allRouteSegments = route.segments;\r\n\r\n for (let i = 0; i < allRouteSegments.length; i++) {\r\n const segmentPath = allRouteSegments.slice(0, i + 1);\r\n\r\n // Try to find layout in manifest first (more efficient)\r\n let layoutManifest: ManifestRouteEntry | undefined;\r\n if (routesManifest) {\r\n layoutManifest = routesManifest.find((r) => {\r\n if (r.type !== \"layout\") return false;\r\n if (r.isRootLayout) return false;\r\n\r\n // Check if segments match (considering all segments including route groups)\r\n if (r.segments.length !== segmentPath.length) return false;\r\n\r\n // Match segments: exact match, dynamic params, or route groups\r\n return r.segments.every((seg, idx) => {\r\n const routeSeg = segmentPath[idx];\r\n \r\n // Exact segment match (including route groups with parentheses)\r\n if (seg.segment === routeSeg.segment) return true;\r\n \r\n // Both dynamic with same param name\r\n if (\r\n seg.isDynamic &&\r\n routeSeg.isDynamic &&\r\n seg.paramName === routeSeg.paramName\r\n ) {\r\n return true;\r\n }\r\n \r\n // Route groups: if both are optional and have the same name\r\n // Compare names without parentheses: (admin) -> admin\r\n if (seg.isOptional && routeSeg.isOptional && !seg.isDynamic && !routeSeg.isDynamic) {\r\n // Extract name without parentheses for comparison\r\n const segName = seg.segment.replace(/^\\(|\\)$/g, '');\r\n const routeSegName = routeSeg.segment.replace(/^\\(|\\)$/g, '');\r\n if (segName === routeSegName) return true;\r\n }\r\n \r\n return false;\r\n });\r\n });\r\n }\r\n\r\n // If found in manifest, use it\r\n if (layoutManifest) {\r\n const layoutSourcePath = resolve(layoutManifest.sourcePath);\r\n const layoutCompiledPath = layoutManifest.serverPath\r\n ? resolve(layoutManifest.serverPath)\r\n : undefined;\r\n\r\n try {\r\n const layoutFile: RouteFile = {\r\n filePath: layoutSourcePath,\r\n segments: layoutManifest.segments,\r\n type: \"layout\",\r\n isRootLayout: false,\r\n urlPath: \"\",\r\n };\r\n\r\n const layout = await this.loadLayoutComponent(\r\n layoutFile,\r\n layoutCompiledPath\r\n );\r\n layouts.push(layout);\r\n } catch (error) {\r\n // Layout not found or failed to load, continue\r\n console.warn(\r\n `[loly-core] Failed to load nested layout at ${layoutSourcePath}:`,\r\n error\r\n );\r\n }\r\n } else {\r\n // If not found in manifest, try to find layout in file system\r\n // This is useful for development mode or when manifest is not available\r\n // Build file path considering all segments (including route groups)\r\n const layoutPathParts = segmentPath.map(s => s.segment);\r\n const layoutDir = join(appDir, ...layoutPathParts);\r\n const layoutFilePath = join(layoutDir, 'layout.tsx');\r\n const layoutFilePathAlt = join(layoutDir, 'layout.ts');\r\n \r\n const actualPath = existsSync(layoutFilePath) \r\n ? layoutFilePath \r\n : existsSync(layoutFilePathAlt) \r\n ? layoutFilePathAlt \r\n : null;\r\n \r\n if (actualPath) {\r\n try {\r\n const layoutFile: RouteFile = {\r\n filePath: actualPath,\r\n segments: segmentPath,\r\n type: \"layout\",\r\n isRootLayout: false,\r\n urlPath: \"\",\r\n };\r\n\r\n const layout = await this.loadLayoutComponent(layoutFile);\r\n layouts.push(layout);\r\n } catch (error) {\r\n console.warn(\r\n `[loly-core] Failed to load nested layout at ${actualPath}:`,\r\n error\r\n );\r\n }\r\n }\r\n }\r\n }\r\n\r\n return layouts;\r\n }\r\n\r\n /**\r\n * Clear component cache\r\n */\r\n clearCache(): void {\r\n this.componentCache.clear();\r\n this.layoutCache.clear();\r\n }\r\n}\r\n\r\n","import { renderToHtml, renderToHtmlStream, createHead, type VChild } from \"loly-jsx\";\r\nimport { registerAsyncTask } from \"../async-registry\";\r\nimport { resolve } from \"path\";\r\nimport type { RouteConfig } from \"../../router/types\";\r\nimport type { RouteConfigWithManifest } from \"../../router/manifest-types\";\r\nimport type { SSRContext, SSRResult } from \"../ssr\";\r\nimport { RouteComponentFactory } from \"../../utils/route-component-factory\";\r\nimport { matchRoute } from \"../../router/matcher\";\r\nimport { getAppDir } from \"../../context\";\r\nimport {\r\n generateErrorHtml,\r\n htmlStringToStream,\r\n extractIslandDataFromHtml,\r\n generateFullHtml,\r\n} from \"../../utils/html\";\r\nimport { getClientAssetsForRoute } from \"../../utils/assets\";\r\nimport { HTTP_STATUS, ERROR_MESSAGES, SERVER } from \"../../constants\";\r\nimport { handleRouteError } from \"../../utils/errors\";\r\nimport { generatePublicEnvScript } from \"../../utils/env\";\r\n\r\n/**\r\n * Rendering strategy interface for SSR\r\n * Defines the contract for different rendering approaches\r\n */\r\nexport interface RenderingStrategy {\r\n /**\r\n * Render content based on the strategy\r\n * @param context - SSR context with pathname, searchParams, etc.\r\n * @param config - Route configuration\r\n * @returns Rendering result with HTML and status\r\n */\r\n render(context: SSRContext, config: RouteConfig): Promise<SSRResult>;\r\n}\r\n\r\n/**\r\n * RSC rendering result\r\n */\r\nexport interface RSCRenderingResult {\r\n html: string;\r\n scripts: string;\r\n styles: string;\r\n preloads: string;\r\n islandData: Record<string, any>;\r\n}\r\n\r\n/**\r\n * RSC (React Server Components) Strategy\r\n * Renders page content without full HTML wrapper for SPA navigation\r\n */\r\nexport class RSCStrategy {\r\n private routeFactory: RouteComponentFactory;\r\n\r\n constructor(routeFactory: RouteComponentFactory) {\r\n this.routeFactory = routeFactory;\r\n }\r\n\r\n async render(\r\n context: SSRContext,\r\n config: RouteConfig\r\n ): Promise<RSCRenderingResult> {\r\n const { pathname } = context;\r\n const appDir = getAppDir();\r\n\r\n // Find matching route\r\n const configWithManifest = config as RouteConfig & RouteConfigWithManifest;\r\n const manifestRouteMap = configWithManifest.routeMapManifest;\r\n const manifestRoute = manifestRouteMap?.get(pathname);\r\n\r\n const match = matchRoute(pathname, config, async (route) => {\r\n const routeManifest =\r\n manifestRouteMap?.get(pathname) ||\r\n Array.from(manifestRouteMap?.values() || []).find(\r\n (r) => r.urlPath === route.urlPath\r\n );\r\n const compiledPath = routeManifest?.serverPath\r\n ? resolve(routeManifest.serverPath)\r\n : undefined;\r\n\r\n return await this.routeFactory.loadRouteComponent(route, compiledPath);\r\n });\r\n\r\n if (!match) {\r\n throw new Error(ERROR_MESSAGES.ROUTE_NOT_FOUND(pathname));\r\n }\r\n\r\n const { route, params } = match;\r\n context.params = params;\r\n\r\n // Load layouts\r\n const layouts = await this.routeFactory.loadLayouts(\r\n route,\r\n config,\r\n appDir,\r\n manifestRoute\r\n );\r\n\r\n // Load page component\r\n const pageCompiledPath = manifestRoute?.serverPath\r\n ? resolve(manifestRoute.serverPath)\r\n : undefined;\r\n const PageComponent = await this.routeFactory.loadRouteComponent(\r\n route,\r\n pageCompiledPath\r\n );\r\n\r\n // Render page with props\r\n const pageProps = {\r\n params,\r\n searchParams: context.searchParams,\r\n };\r\n\r\n let pageContent: VChild;\r\n if (typeof PageComponent === \"function\") {\r\n const result = PageComponent(pageProps);\r\n // Handle async page components\r\n pageContent = result instanceof Promise ? await result : result;\r\n } else {\r\n throw new Error(ERROR_MESSAGES.PAGE_COMPONENT_MUST_BE_FUNCTION);\r\n }\r\n\r\n // Apply layouts (from outermost to innermost)\r\n let content = pageContent;\r\n for (let i = layouts.length - 1; i >= 0; i--) {\r\n const Layout = layouts[i];\r\n if (typeof Layout === \"function\") {\r\n const layoutResult = Layout({ children: content, params });\r\n // Handle async layouts\r\n content =\r\n layoutResult instanceof Promise ? await layoutResult : layoutResult;\r\n }\r\n }\r\n\r\n // Render only the content (without HTML wrapper)\r\n const { renderToString } = await import(\"loly-jsx\");\r\n const htmlWithScripts = await renderToString(content);\r\n\r\n // Extract island data from HTML\r\n const { htmlWithoutScripts, islandData } =\r\n extractIslandDataFromHtml(htmlWithScripts);\r\n\r\n // Get client assets for this route\r\n const { scripts, styles, preloads } = getClientAssetsForRoute(manifestRoute);\r\n\r\n return { html: htmlWithoutScripts, scripts, styles, preloads, islandData };\r\n }\r\n}\r\n\r\n/**\r\n * SSR (Server-Side Rendering) Strategy\r\n * Renders full HTML document with head, body, scripts, and styles\r\n */\r\nexport class SSRStrategy implements RenderingStrategy {\r\n private routeFactory: RouteComponentFactory;\r\n\r\n constructor(routeFactory: RouteComponentFactory) {\r\n this.routeFactory = routeFactory;\r\n }\r\n\r\n async render(context: SSRContext, config: RouteConfig): Promise<SSRResult> {\r\n const { pathname } = context;\r\n const appDir = getAppDir();\r\n\r\n // Find matching route\r\n const configWithManifest = config as RouteConfig & RouteConfigWithManifest;\r\n const manifestRouteMap = configWithManifest.routeMapManifest;\r\n const manifestRoute = manifestRouteMap?.get(pathname);\r\n\r\n const match = matchRoute(pathname, config, async (route) => {\r\n const routeManifest =\r\n manifestRouteMap?.get(pathname) ||\r\n Array.from(manifestRouteMap?.values() || []).find(\r\n (r) => r.urlPath === route.urlPath\r\n );\r\n const compiledPath = routeManifest?.serverPath\r\n ? resolve(routeManifest.serverPath)\r\n : undefined;\r\n\r\n return await this.routeFactory.loadRouteComponent(route, compiledPath);\r\n });\r\n\r\n if (!match) {\r\n return {\r\n html: htmlStringToStream(generateErrorHtml(HTTP_STATUS.NOT_FOUND, \"\")),\r\n status: HTTP_STATUS.NOT_FOUND,\r\n };\r\n }\r\n\r\n const { route, params } = match;\r\n context.params = params;\r\n\r\n try {\r\n // Load layouts\r\n const layouts = await this.routeFactory.loadLayouts(\r\n route,\r\n config,\r\n appDir,\r\n manifestRoute\r\n );\r\n\r\n // Load page component\r\n const pageCompiledPath = manifestRoute?.serverPath\r\n ? resolve(manifestRoute.serverPath)\r\n : undefined;\r\n const PageComponent = await this.routeFactory.loadRouteComponent(\r\n route,\r\n pageCompiledPath\r\n );\r\n\r\n // Render page with props\r\n const pageProps = {\r\n params,\r\n searchParams: context.searchParams,\r\n };\r\n\r\n let pageContent: VChild;\r\n if (typeof PageComponent === \"function\") {\r\n const result = PageComponent(pageProps);\r\n // Handle async page components\r\n pageContent = result instanceof Promise ? await result : result;\r\n } else {\r\n throw new Error(ERROR_MESSAGES.PAGE_COMPONENT_MUST_BE_FUNCTION);\r\n }\r\n\r\n // Apply layouts\r\n let content = pageContent;\r\n for (let i = layouts.length - 1; i >= 0; i--) {\r\n const Layout = layouts[i];\r\n\r\n if (typeof Layout === \"function\") {\r\n const layoutResult = Layout({ children: content, params });\r\n // Handle async layouts\r\n content =\r\n layoutResult instanceof Promise ? await layoutResult : layoutResult;\r\n }\r\n }\r\n\r\n // Create head\r\n const head = createHead();\r\n head.setTitle(\"Loly App\");\r\n\r\n // Get client assets for this route\r\n const { scripts, styles, preloads } = getClientAssetsForRoute(manifestRoute);\r\n\r\n // Inject public env variables script\r\n const envScript = generatePublicEnvScript();\r\n\r\n // Add preloads and env script to head (modulepreload for main script)\r\n // Preloads should be in the head for early discovery\r\n const headParts = [head.toString()];\r\n if (preloads) headParts.push(preloads);\r\n headParts.push(envScript);\r\n const headContent = headParts.join(\"\\n\");\r\n\r\n // Render to HTML using streaming\r\n // Pass onAsyncTask callback to register async tasks in the registry\r\n const htmlStream = renderToHtmlStream({\r\n view: content,\r\n head: headContent,\r\n scripts,\r\n styles,\r\n appId: SERVER.APP_CONTAINER_ID,\r\n onAsyncTask: (id, fn, props) => {\r\n registerAsyncTask(id, fn, props);\r\n },\r\n });\r\n\r\n return {\r\n html: htmlStream,\r\n status: HTTP_STATUS.OK,\r\n };\r\n } catch (error) {\r\n return handleRouteError(error as Error, context.pathname);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Factory for creating rendering strategies\r\n */\r\nexport class RenderingStrategyFactory {\r\n private routeFactory: RouteComponentFactory;\r\n\r\n constructor(routeFactory: RouteComponentFactory) {\r\n this.routeFactory = routeFactory;\r\n }\r\n\r\n /**\r\n * Get SSR rendering strategy\r\n * @returns SSR rendering strategy\r\n */\r\n getSSRStrategy(): SSRStrategy {\r\n return new SSRStrategy(this.routeFactory);\r\n }\r\n\r\n /**\r\n * Get RSC rendering strategy\r\n * @returns RSC rendering strategy\r\n */\r\n getRSCStrategy(): RSCStrategy {\r\n return new RSCStrategy(this.routeFactory);\r\n }\r\n\r\n /**\r\n * Get rendering strategy based on type\r\n * @param type - Strategy type: 'ssr' or 'rsc'\r\n * @returns Appropriate rendering strategy (SSR only, RSC must be accessed via getRSCStrategy)\r\n */\r\n getStrategy(type: \"ssr\"): RenderingStrategy {\r\n if (type === \"ssr\") {\r\n return new SSRStrategy(this.routeFactory);\r\n }\r\n throw new Error(`Invalid strategy type: ${type}`);\r\n }\r\n}\r\n\r\n","import type { VChild } from \"loly-jsx\";\r\n\r\n/**\r\n * Async task stored in registry\r\n */\r\nexport interface AsyncTask {\r\n id: string;\r\n fn: () => Promise<VChild>;\r\n props?: Record<string, unknown>;\r\n createdAt: number;\r\n}\r\n\r\n/**\r\n * In-memory registry for async tasks\r\n * Key: async ID, Value: AsyncTask\r\n */\r\nconst asyncTaskRegistry = new Map<string, AsyncTask>();\r\n\r\n/**\r\n * Default max age for tasks (5 minutes)\r\n */\r\nconst DEFAULT_MAX_AGE = 5 * 60 * 1000; // 5 minutes\r\n\r\n/**\r\n * Register an async task in the registry\r\n */\r\nexport function registerAsyncTask(\r\n id: string,\r\n fn: () => Promise<VChild>,\r\n props?: Record<string, unknown>\r\n): void {\r\n asyncTaskRegistry.set(id, {\r\n id,\r\n fn,\r\n props,\r\n createdAt: Date.now(),\r\n });\r\n}\r\n\r\n/**\r\n * Get an async task from the registry\r\n */\r\nexport function getAsyncTask(id: string): AsyncTask | undefined {\r\n return asyncTaskRegistry.get(id);\r\n}\r\n\r\n/**\r\n * Resolve an async task (execute the Promise function)\r\n */\r\nexport async function resolveAsyncTask(id: string): Promise<VChild> {\r\n const task = asyncTaskRegistry.get(id);\r\n if (!task) {\r\n throw new Error(`Async task not found: ${id}`);\r\n }\r\n return task.fn();\r\n}\r\n\r\n/**\r\n * Remove an async task from the registry\r\n */\r\nexport function removeAsyncTask(id: string): void {\r\n asyncTaskRegistry.delete(id);\r\n}\r\n\r\n/**\r\n * Clean up expired tasks from the registry\r\n */\r\nexport function cleanupExpiredTasks(maxAge: number = DEFAULT_MAX_AGE): void {\r\n const now = Date.now();\r\n for (const [id, task] of asyncTaskRegistry.entries()) {\r\n if (now - task.createdAt > maxAge) {\r\n asyncTaskRegistry.delete(id);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get the size of the registry (for debugging/monitoring)\r\n */\r\nexport function getRegistrySize(): number {\r\n return asyncTaskRegistry.size;\r\n}\r\n\r\n/**\r\n * Clear all tasks from the registry (for testing)\r\n */\r\nexport function clearRegistry(): void {\r\n asyncTaskRegistry.clear();\r\n}\r\n\r\n","import { join } from \"path\";\r\nimport { DIRECTORIES, FILE_NAMES, ERROR_MESSAGES } from \"./constants\";\r\nimport type { RouteConfig } from \"./router/types\";\r\n\r\nexport interface FrameworkContext {\r\n projectDir: string;\r\n appDir: string;\r\n srcDir: string;\r\n outDir: string;\r\n // New additions:\r\n routeConfig?: RouteConfig | null;\r\n buildMode?: \"development\" | \"production\";\r\n serverPort?: number;\r\n isDev?: boolean;\r\n}\r\n\r\nlet globalContext: FrameworkContext | null = null;\r\n\r\n/**\r\n * Set the framework context (should be called at the start of each command)\r\n */\r\nexport function setContext(context: FrameworkContext): void {\r\n globalContext = context;\r\n}\r\n\r\n/**\r\n * Get the framework context\r\n * @throws Error if context is not initialized\r\n */\r\nexport function getContext(): FrameworkContext {\r\n if (!globalContext) {\r\n throw new Error(ERROR_MESSAGES.CONTEXT_NOT_INITIALIZED);\r\n }\r\n return globalContext;\r\n}\r\n\r\n/**\r\n * Get project directory\r\n */\r\nexport function getProjectDir(): string {\r\n return getContext().projectDir;\r\n}\r\n\r\n/**\r\n * Get app directory (src/app/)\r\n */\r\nexport function getAppDir(): string {\r\n return getContext().appDir;\r\n}\r\n\r\n/**\r\n * Get src directory\r\n */\r\nexport function getSrcDir(): string {\r\n return getContext().srcDir;\r\n}\r\n\r\n/**\r\n * Get output directory\r\n */\r\nexport function getOutDir(): string {\r\n return getContext().outDir;\r\n}\r\n\r\n/**\r\n * Get app directory path for a given project directory\r\n * Always returns src/app/ (no backward compatibility)\r\n */\r\nexport function getAppDirPath(projectDir: string): string {\r\n return join(projectDir, DIRECTORIES.SRC, DIRECTORIES.APP);\r\n}\r\n\r\n/**\r\n * Get client output directory (.loly/dist/client)\r\n */\r\nexport function getClientDir(): string {\r\n return join(getOutDir(), DIRECTORIES.CLIENT);\r\n}\r\n\r\n/**\r\n * Get server output directory (.loly/dist/server)\r\n */\r\nexport function getServerOutDir(): string {\r\n return join(getOutDir(), DIRECTORIES.SERVER);\r\n}\r\n\r\n/**\r\n * Get client manifest path (.loly/dist/client/manifest.json)\r\n */\r\nexport function getManifestPath(): string {\r\n return join(getClientDir(), FILE_NAMES.MANIFEST);\r\n}\r\n\r\n/**\r\n * Get routes manifest path (.loly/routes-manifest.json)\r\n */\r\nexport function getRoutesManifestPath(): string {\r\n return join(getProjectDir(), DIRECTORIES.LOLY, FILE_NAMES.ROUTES_MANIFEST);\r\n}\r\n\r\n/**\r\n * Get bootstrap path (.loly/bootstrap.ts)\r\n */\r\nexport function getBootstrapPath(): string {\r\n return join(getProjectDir(), DIRECTORIES.LOLY, FILE_NAMES.BOOTSTRAP);\r\n}\r\n\r\n/**\r\n * Get globals.css path in client output (.loly/dist/client/globals.css)\r\n */\r\nexport function getGlobalsCssPath(): string {\r\n return join(getClientDir(), FILE_NAMES.GLOBALS_CSS);\r\n}\r\n\r\n/**\r\n * Get public directory path (public/)\r\n */\r\nexport function getPublicDir(): string {\r\n return join(getProjectDir(), DIRECTORIES.PUBLIC);\r\n}\r\n\r\n/**\r\n * Get route configuration from context\r\n */\r\nexport function getRouteConfig(): RouteConfig | null {\r\n return getContext().routeConfig || null;\r\n}\r\n\r\n/**\r\n * Set route configuration in context\r\n */\r\nexport function setRouteConfig(config: RouteConfig): void {\r\n const context = getContext();\r\n context.routeConfig = config;\r\n}\r\n\r\n/**\r\n * Get build mode from context\r\n */\r\nexport function getBuildMode(): \"development\" | \"production\" | undefined {\r\n return getContext().buildMode;\r\n}\r\n\r\n/**\r\n * Check if running in development mode\r\n */\r\nexport function isDevelopment(): boolean {\r\n const context = getContext();\r\n return context.isDev ?? context.buildMode === \"development\";\r\n}\r\n\r\n","import { HTTP_STATUS } from \"../constants/http\";\r\n\r\n/**\r\n * Result of extracting island data from HTML\r\n */\r\nexport interface ExtractResult {\r\n htmlWithoutScripts: string;\r\n islandData: Record<string, any>;\r\n}\r\n\r\n/**\r\n * Generate error page HTML\r\n */\r\nexport function generateErrorHtml(\r\n status: number,\r\n message: string\r\n): string {\r\n const statusText =\r\n status === HTTP_STATUS.NOT_FOUND\r\n ? \"404 - Not Found\"\r\n : status === HTTP_STATUS.INTERNAL_ERROR\r\n ? \"500 - Internal Server Error\"\r\n : `${status} - Error`;\r\n\r\n return `<!doctype html><html><head><title>${statusText}</title></head><body><h1>${statusText}</h1>${message ? `<p>${message}</p>` : \"\"}</body></html>`;\r\n}\r\n\r\n/**\r\n * Convert HTML string to ReadableStream\r\n */\r\nexport function htmlStringToStream(html: string): ReadableStream<Uint8Array> {\r\n const encoder = new TextEncoder();\r\n return new ReadableStream({\r\n start(controller) {\r\n controller.enqueue(encoder.encode(html));\r\n controller.close();\r\n },\r\n });\r\n}\r\n\r\n/**\r\n * Generate full HTML document\r\n */\r\nexport function generateFullHtml(\r\n head: string,\r\n body: string,\r\n scripts: string,\r\n styles: string\r\n): string {\r\n return `<!doctype html><html><head>${head}${styles}</head><body><div id=\"app\">${body}</div>${scripts}</body></html>`;\r\n}\r\n\r\n/**\r\n * Extract island data scripts from HTML and return clean HTML + island data\r\n */\r\nexport function extractIslandDataFromHtml(html: string): ExtractResult {\r\n const islandData: Record<string, any> = {};\r\n\r\n // Pattern: <script>window.__LOLY_ISLAND_DATA__=window.__LOLY_ISLAND_DATA__||{};window.__LOLY_ISLAND_DATA__[ID]=DATA;</script>\r\n // Match script tags that contain island data initialization\r\n const islandDataRegex =\r\n /<script>window\\.__LOLY_ISLAND_DATA__=window\\.__LOLY_ISLAND_DATA__\\|\\|{};window\\.__LOLY_ISLAND_DATA__\\[([^\\]]+)\\]=([^<]+);<\\/script>/gs;\r\n\r\n const htmlWithoutScripts = html.replace(\r\n islandDataRegex,\r\n (match, id, data) => {\r\n try {\r\n // Parse the island ID (could be string in quotes or number)\r\n let islandId: string;\r\n const trimmedId = id.trim();\r\n if (trimmedId.startsWith('\"') || trimmedId.startsWith(\"'\")) {\r\n islandId = JSON.parse(trimmedId);\r\n } else if (/^\\d+$/.test(trimmedId)) {\r\n islandId = trimmedId; // Keep as string key\r\n } else {\r\n islandId = trimmedId; // Use as-is\r\n }\r\n\r\n // Parse the island props data (remove trailing semicolon if present)\r\n const trimmedData = data.trim().replace(/;?\\s*$/, \"\");\r\n const islandProps = JSON.parse(trimmedData);\r\n islandData[islandId] = islandProps;\r\n } catch (e) {\r\n console.warn(\r\n \"[loly-core] Failed to parse island data:\",\r\n e,\r\n { id, data: data?.substring(0, 100) }\r\n );\r\n }\r\n return \"\"; // Remove script tag from HTML\r\n }\r\n );\r\n\r\n return { htmlWithoutScripts, islandData };\r\n}\r\n\r\n","import { existsSync, readFileSync } from \"fs\";\r\nimport { getManifestPath, getGlobalsCssPath } from \"../context\";\r\n\r\n/**\r\n * Asset tags (scripts, styles, and preloads)\r\n */\r\nexport interface AssetTags {\r\n scripts: string;\r\n styles: string;\r\n preloads: string;\r\n}\r\n\r\n/**\r\n * Get main.js filename from client manifest (Rspack format)\r\n */\r\nexport function getMainScriptName(): string {\r\n const manifestPath = getManifestPath();\r\n\r\n if (!existsSync(manifestPath)) {\r\n return \"main.js\"; // Fallback\r\n }\r\n\r\n try {\r\n // Read Rspack manifest (not Vite format)\r\n const manifestContent = readFileSync(manifestPath, \"utf-8\");\r\n const manifest = JSON.parse(manifestContent);\r\n\r\n // Rspack manifest format: { \"main\": { \"file\": \"main.[hash].js\", ... } }\r\n const mainEntry = manifest[\"main\"];\r\n if (mainEntry?.file) {\r\n return mainEntry.file;\r\n }\r\n } catch (error) {\r\n console.warn(\"[loly-core] Failed to read client manifest:\", error);\r\n }\r\n\r\n return \"main.js\"; // Fallback\r\n}\r\n\r\n/**\r\n * Generate client asset tags from route chunks\r\n */\r\nexport function generateAssetTags(\r\n manifestRoute: any,\r\n publicPath: string = \"/\"\r\n): AssetTags {\r\n let scripts = \"\";\r\n let styles = \"\";\r\n let preloads = \"\";\r\n\r\n // Always include main bootstrap script\r\n const mainScriptName = getMainScriptName();\r\n const mainScriptPath = mainScriptName.startsWith(\"/\")\r\n ? mainScriptName\r\n : `${publicPath}${mainScriptName}`;\r\n \r\n // Preload main script for faster loading (critical for activation)\r\n // Using modulepreload for ES modules (better than preload)\r\n preloads = `<link rel=\"modulepreload\" href=\"${mainScriptPath}\" crossorigin>`;\r\n \r\n scripts = `<script type=\"module\" src=\"${mainScriptPath}\"></script>`;\r\n\r\n // Always include global styles if they exist (copied directly to client output)\r\n const globalsCssPath = getGlobalsCssPath();\r\n if (existsSync(globalsCssPath)) {\r\n const cssPath = `${publicPath}globals.css`;\r\n // Use blocking stylesheet to prevent CLS (especially important with streaming SSR)\r\n // CSS should be render-blocking to avoid layout shifts\r\n styles += `\\n<link rel=\"stylesheet\" href=\"${cssPath}\">`;\r\n }\r\n\r\n // Add route-specific chunks if available\r\n // Note: We don't preload route chunks - they load on demand\r\n if (manifestRoute?.clientChunks) {\r\n const { js = [], css = [] } = manifestRoute.clientChunks;\r\n\r\n // Add JS chunks (no preload - lazy loaded)\r\n for (const jsFile of js) {\r\n const scriptPath = jsFile.startsWith(\"/\") ? jsFile : `${publicPath}${jsFile}`;\r\n scripts += `\\n<script type=\"module\" src=\"${scriptPath}\"></script>`;\r\n }\r\n\r\n // Add CSS chunks (route-specific, in addition to global styles)\r\n for (const cssFile of css) {\r\n const cssPath = cssFile.startsWith(\"/\") ? cssFile : `${publicPath}${cssFile}`;\r\n styles += `\\n<link rel=\"stylesheet\" href=\"${cssPath}\">`;\r\n }\r\n }\r\n\r\n return { scripts, styles, preloads };\r\n}\r\n\r\n/**\r\n * Get client assets for a specific route from routes-manifest\r\n */\r\nexport function getClientAssetsForRoute(\r\n manifestRoute: any\r\n): AssetTags {\r\n return generateAssetTags(manifestRoute, \"/\");\r\n}\r\n\r\n","import { HTTP_STATUS } from \"../constants/http\";\r\nimport { ERROR_MESSAGES } from \"../constants/errors\";\r\nimport type { SSRResult } from \"../server/ssr\";\r\nimport { generateErrorHtml, htmlStringToStream } from \"./html\";\r\n\r\n/**\r\n * Handle route errors and return appropriate SSR result\r\n */\r\nexport function handleRouteError(\r\n error: Error,\r\n pathname: string\r\n): SSRResult {\r\n if (error.message.includes(\"Route not found\")) {\r\n return {\r\n html: htmlStringToStream(generateErrorHtml(HTTP_STATUS.NOT_FOUND, \"\")),\r\n status: HTTP_STATUS.NOT_FOUND,\r\n };\r\n }\r\n\r\n console.error(ERROR_MESSAGES.ERROR_RENDERING_PAGE, error);\r\n return {\r\n html: htmlStringToStream(generateErrorHtml(HTTP_STATUS.INTERNAL_ERROR, \"\")),\r\n status: HTTP_STATUS.INTERNAL_ERROR,\r\n };\r\n}\r\n\r\n/**\r\n * Handle module load errors\r\n */\r\nexport function handleModuleLoadError(\r\n error: Error,\r\n path: string\r\n): never {\r\n console.error(ERROR_MESSAGES.FAILED_TO_LOAD_MODULE(path), error);\r\n throw error;\r\n}\r\n\r\n","/**\r\n * Extract public environment variables (LOLY_PUBLIC_*)\r\n * These variables will be available in the client\r\n */\r\nexport function getPublicEnv(): Record<string, string> {\r\n const publicEnv: Record<string, string> = {};\r\n\r\n if (typeof process !== \"undefined\" && process.env) {\r\n for (const key in process.env) {\r\n if (key.startsWith(\"LOLY_PUBLIC_\")) {\r\n // Remove LOLY_PUBLIC_ prefix for client access\r\n const clientKey = key.replace(/^LOLY_PUBLIC_/, \"\");\r\n publicEnv[clientKey] = process.env[key] || \"\";\r\n }\r\n }\r\n }\r\n\r\n return publicEnv;\r\n}\r\n\r\n/**\r\n * Generate script tag to inject public env variables into client\r\n */\r\nexport function generatePublicEnvScript(): string {\r\n const publicEnv = getPublicEnv();\r\n const envJson = JSON.stringify(publicEnv);\r\n return `<script>window.__LOLY_ENV__=Object.freeze(${envJson});</script>`;\r\n}\r\n\r\n/**\r\n * Get public environment variable (works in both server and client)\r\n * In server: reads from process.env (with or without LOLY_PUBLIC_ prefix)\r\n * In client: reads from window.__LOLY_ENV__\r\n */\r\nexport function getEnv(key: string): string | undefined {\r\n if (typeof window !== \"undefined\" && (window as any).__LOLY_ENV__) {\r\n // Client side\r\n return (window as any).__LOLY_ENV__[key];\r\n }\r\n\r\n if (typeof process !== \"undefined\" && process.env) {\r\n // Server side - try both with and without prefix\r\n return process.env[key] || process.env[`LOLY_PUBLIC_${key}`];\r\n }\r\n\r\n return undefined;\r\n}\r\n\r\n","import type { RouteConfig } from \"../router/types\";\r\nimport { RouteComponentFactory } from \"../utils/route-component-factory\";\r\nimport { RSCStrategy, SSRStrategy } from \"./rendering/strategies\";\r\n\r\n// Singleton instance of route component factory\r\nconst routeFactory = new RouteComponentFactory();\r\n\r\nexport interface SSRContext {\r\n pathname: string;\r\n searchParams: Record<string, string>;\r\n params: Record<string, string>;\r\n}\r\n\r\nexport interface SSRResult {\r\n html: ReadableStream<Uint8Array>;\r\n status: number;\r\n}\r\n\r\n\r\n\r\n\r\n/**\r\n * Render page content (without full HTML wrapper) - used for RSC endpoint\r\n */\r\nexport async function renderPageContent(\r\n context: SSRContext,\r\n config: RouteConfig,\r\n appDir: string\r\n): Promise<{ html: string; scripts: string; styles: string; preloads: string; islandData: Record<string, any> }> {\r\n const rscStrategy = new RSCStrategy(routeFactory);\r\n return await rscStrategy.render(context, config);\r\n}\r\n\r\n/**\r\n * Render a page using streaming\r\n */\r\nexport async function renderPageStream(\r\n context: SSRContext,\r\n config: RouteConfig,\r\n appDir: string\r\n): Promise<SSRResult> {\r\n const ssrStrategy = new SSRStrategy(routeFactory);\r\n return await ssrStrategy.render(context, config);\r\n}\r\n\r\n","import express, { type Express } from \"express\";\r\nimport type { RouteConfig } from \"../router/types\";\r\nimport {\r\n getClientDir,\r\n getPublicDir,\r\n getAppDir,\r\n getRouteConfig,\r\n} from \"../context\";\r\nimport {\r\n setupExpressMiddleware,\r\n setupStaticFiles,\r\n setupRSCEndpoint,\r\n setupSSREndpoint,\r\n setupImageEndpoint,\r\n setupAsyncEndpoint,\r\n setupApiRoutes,\r\n type RSCHandler,\r\n type SSRHandler,\r\n} from \"../utils/express-setup\";\r\nimport { SERVER } from \"../constants\";\r\nimport { renderPageStream, renderPageContent } from \"./ssr\";\r\n\r\n/**\r\n * Abstract base server class using Template Method pattern\r\n * Defines the skeleton of server setup algorithm\r\n */\r\nexport abstract class BaseServer {\r\n protected app: Express;\r\n protected port: number;\r\n\r\n constructor(port: number = SERVER.DEFAULT_PORT) {\r\n this.app = express();\r\n this.port = port;\r\n }\r\n\r\n /**\r\n * Template method - defines the algorithm structure\r\n */\r\n async setup(): Promise<void> {\r\n this.setupMiddleware();\r\n this.setupStaticFiles();\r\n this.setupImageEndpoint();\r\n this.setupAsyncEndpoint();\r\n this.setupApiRoutes();\r\n this.setupRSCEndpoint();\r\n this.setupSSREndpoint();\r\n }\r\n\r\n /**\r\n * Setup Express middleware\r\n */\r\n protected setupMiddleware(): void {\r\n setupExpressMiddleware(this.app);\r\n }\r\n\r\n /**\r\n * Setup static file serving\r\n */\r\n protected setupStaticFiles(): void {\r\n setupStaticFiles(this.app, getClientDir(), getPublicDir());\r\n }\r\n\r\n /**\r\n * Setup image optimization endpoint\r\n */\r\n protected setupImageEndpoint(): void {\r\n setupImageEndpoint(this.app);\r\n }\r\n\r\n /**\r\n * Setup async component endpoint\r\n */\r\n protected setupAsyncEndpoint(): void {\r\n setupAsyncEndpoint(this.app);\r\n }\r\n\r\n /**\r\n * Setup API routes\r\n */\r\n protected setupApiRoutes(): void {\r\n setupApiRoutes(this.app, () => {\r\n try {\r\n return getRouteConfig();\r\n } catch {\r\n return null;\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Setup RSC endpoint\r\n */\r\n protected setupRSCEndpoint(): void {\r\n setupRSCEndpoint(this.app, this.createRSCHandler());\r\n }\r\n\r\n /**\r\n * Setup SSR endpoint\r\n */\r\n protected setupSSREndpoint(): void {\r\n setupSSREndpoint(this.app, this.createSSRHandler());\r\n }\r\n\r\n /**\r\n * Create RSC handler - to be implemented by subclasses\r\n */\r\n protected abstract createRSCHandler(): RSCHandler;\r\n\r\n /**\r\n * Create SSR handler - to be implemented by subclasses\r\n */\r\n protected abstract createSSRHandler(): SSRHandler;\r\n\r\n /**\r\n * Load route configuration - to be implemented by subclasses\r\n */\r\n protected abstract loadRouteConfig(): Promise<RouteConfig>;\r\n\r\n /**\r\n * Start the server\r\n */\r\n async start(): Promise<void> {\r\n await this.setup();\r\n this.app.listen(this.port, () => {\r\n console.log(\r\n `[loly-core] Server running at http://localhost:${this.port}`\r\n );\r\n });\r\n }\r\n\r\n /**\r\n * Get the Express app instance\r\n */\r\n getApp(): Express {\r\n return this.app;\r\n }\r\n}\r\n\r\n","import express, { type Express, type Request, type Response } from \"express\";\r\nimport { Readable } from \"stream\";\r\nimport { existsSync } from \"fs\";\r\nimport { HTTP_HEADERS, HTTP_STATUS, SERVER } from \"../constants\";\r\nimport { ERROR_MESSAGES } from \"../constants/errors\";\r\nimport type { SSRResult } from \"../server/ssr\";\r\nimport type { RouteConfig } from \"../router/types\";\r\nimport { handleImageRequest } from \"../server/handlers/image\";\r\nimport type { ImageConfig } from \"../server/utils/image-validation\";\r\nimport { createApiRouteHandler } from \"../server/handlers/api-route\";\r\nimport { handleAsyncRequest } from \"../server/handlers/async-handler\";\r\nimport compression from \"compression\";\r\n\r\n/**\r\n * Setup Express middleware for query params parsing\r\n */\r\nexport function setupExpressMiddleware(app: Express): void {\r\n // Add compression middleware (gzip/deflate) - should be early in the middleware stack\r\n app.use(compression({\r\n level: 6, // Compression level (1-9, 6 is good balance)\r\n threshold: 1024, // Only compress responses > 1KB\r\n filter: (req: Request, res: Response) => {\r\n // Don't compress if client doesn't support it\r\n if (req.headers['x-no-compression']) {\r\n return false;\r\n }\r\n // Use compression for all text-based content\r\n return compression.filter(req, res);\r\n }\r\n }));\r\n\r\n app.use((req, res, next) => {\r\n const url = new URL(req.url, `http://${req.headers.host}`);\r\n req.query = Object.fromEntries(url.searchParams);\r\n next();\r\n });\r\n}\r\n\r\n/**\r\n * Setup static file serving for client build and public directory\r\n */\r\nexport function setupStaticFiles(\r\n app: Express,\r\n clientDir: string,\r\n publicDir: string\r\n): void {\r\n // Serve static files from client build\r\n if (existsSync(clientDir)) {\r\n app.use(express.static(clientDir));\r\n } else {\r\n console.warn(ERROR_MESSAGES.CLIENT_BUILD_DIR_NOT_FOUND(clientDir));\r\n }\r\n\r\n // Serve static files from public/\r\n if (existsSync(publicDir)) {\r\n app.use(express.static(publicDir));\r\n }\r\n}\r\n\r\n/**\r\n * Handler for RSC endpoint\r\n */\r\nexport type RSCHandler = (\r\n pathname: string,\r\n searchParams: Record<string, string>\r\n) => Promise<{\r\n html: string;\r\n scripts: string;\r\n styles: string;\r\n preloads: string;\r\n islandData?: Record<string, any>;\r\n params: Record<string, string>;\r\n}>;\r\n\r\n/**\r\n * Setup RSC endpoint for SPA navigation\r\n */\r\nexport function setupRSCEndpoint(app: Express, handler: RSCHandler): void {\r\n app.get(SERVER.RSC_ENDPOINT, async (req: Request, res: Response) => {\r\n try {\r\n const pathname = (req.query.path as string) || \"/\";\r\n const search = (req.query.search as string) || \"\";\r\n const searchParams = search\r\n ? Object.fromEntries(new URLSearchParams(search))\r\n : {};\r\n\r\n const result = await handler(pathname, searchParams);\r\n\r\n res.setHeader(\"Content-Type\", HTTP_HEADERS.CONTENT_TYPE_JSON);\r\n res.json({\r\n pathname,\r\n params: result.params,\r\n searchParams,\r\n html: result.html,\r\n scripts: result.scripts,\r\n styles: result.styles,\r\n preloads: result.preloads,\r\n islandData: result.islandData,\r\n });\r\n } catch (error) {\r\n console.error(ERROR_MESSAGES.RSC_ENDPOINT_ERROR, error);\r\n if ((error as Error).message.includes(\"Route not found\")) {\r\n res.status(HTTP_STATUS.NOT_FOUND).json({ error: \"Route not found\" });\r\n } else {\r\n res.status(HTTP_STATUS.INTERNAL_ERROR).json({\r\n error: \"Internal Server Error\",\r\n });\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Handler for SSR endpoint\r\n */\r\nexport type SSRHandler = (\r\n pathname: string,\r\n searchParams: Record<string, string>\r\n) => Promise<SSRResult>;\r\n\r\n/**\r\n * Handler for API routes\r\n */\r\nexport type ApiRouteHandler = (\r\n pathname: string,\r\n method: string,\r\n req: Request,\r\n res: Response,\r\n config: RouteConfig\r\n) => Promise<void>;\r\n\r\n/**\r\n * Setup image optimization endpoint\r\n * Must be registered before catch-all routes\r\n */\r\nexport function setupImageEndpoint(app: Express, config?: ImageConfig): void {\r\n app.get(SERVER.IMAGE_ENDPOINT, async (req: Request, res: Response) => {\r\n await handleImageRequest({ req, res, config });\r\n });\r\n}\r\n\r\n/**\r\n * Setup async component endpoint\r\n * Must be registered before catch-all routes\r\n */\r\nexport function setupAsyncEndpoint(app: Express): void {\r\n app.get(`${SERVER.ASYNC_ENDPOINT}/:id`, async (req: Request, res: Response) => {\r\n await handleAsyncRequest(req, res);\r\n });\r\n}\r\n\r\n/**\r\n * Setup API routes from route configuration\r\n * Must be registered before SSR endpoint (catch-all)\r\n * \r\n * This registers a middleware that:\r\n * 1. Checks if the request path matches any API route\r\n * 2. If matched, loads and executes the appropriate HTTP method handler\r\n * 3. If not matched, continues to next middleware (SSR)\r\n */\r\nexport function setupApiRoutes(app: Express, getConfig: () => RouteConfig | null): void {\r\n // Add JSON body parsing middleware for API routes\r\n // This is needed for POST, PUT, PATCH requests\r\n app.use(express.json({ limit: \"10mb\" }));\r\n app.use(express.urlencoded({ extended: true, limit: \"10mb\" }));\r\n\r\n // Create the API route handler\r\n const apiHandler = createApiRouteHandler();\r\n\r\n // Register middleware that handles all HTTP methods for API routes\r\n // This runs before the SSR catch-all route\r\n app.use(async (req: Request, res: Response, next) => {\r\n const config = getConfig();\r\n if (!config) {\r\n return next(); // No config available yet, skip to SSR\r\n }\r\n\r\n const url = new URL(req.url, `http://${req.headers.host}`);\r\n const pathname = url.pathname;\r\n const method = req.method;\r\n\r\n // Check if this might be an API route\r\n // API routes should have at least one API route defined\r\n if (config.apiRouteMap && config.apiRouteMap.size > 0) {\r\n // Try to match and handle as API route\r\n try {\r\n const handled = await apiHandler(pathname, method, req, res, config);\r\n // If route was matched and handled, don't continue to SSR\r\n if (handled) {\r\n return;\r\n }\r\n // Route not found - continue to SSR\r\n } catch (error) {\r\n // If there's an error and headers not sent, let SSR handle it\r\n if (!res.headersSent) {\r\n return next();\r\n }\r\n // If headers were sent, error was already handled\r\n return;\r\n }\r\n }\r\n\r\n // Continue to next middleware (SSR)\r\n next();\r\n });\r\n}\r\n\r\n/**\r\n * Setup SSR endpoint for main route handling\r\n */\r\nexport function setupSSREndpoint(app: Express, handler: SSRHandler): void {\r\n app.get(\"*\", async (req: Request, res: Response) => {\r\n try {\r\n const url = new URL(req.url, `http://${req.headers.host}`);\r\n\r\n const result = await handler(\r\n url.pathname,\r\n Object.fromEntries(url.searchParams)\r\n );\r\n\r\n res.status(result.status);\r\n res.setHeader(\"Content-Type\", HTTP_HEADERS.CONTENT_TYPE_HTML);\r\n \r\n // Convert ReadableStream to Node.js Readable stream and pipe to response\r\n // @ts-expect-error - ReadableStream type compatibility between global and Node.js stream/web\r\n const nodeStream = Readable.fromWeb(result.html);\r\n nodeStream.pipe(res);\r\n \r\n // Handle stream errors\r\n nodeStream.on(\"error\", (err) => {\r\n if (!res.headersSent) {\r\n console.error(ERROR_MESSAGES.ERROR_HANDLING_REQUEST, err);\r\n res.status(HTTP_STATUS.INTERNAL_ERROR).send(\"Internal Server Error\");\r\n }\r\n });\r\n } catch (error) {\r\n console.error(ERROR_MESSAGES.ERROR_HANDLING_REQUEST, error);\r\n res.status(HTTP_STATUS.INTERNAL_ERROR).send(\"Internal Server Error\");\r\n }\r\n });\r\n}\r\n\r\n","import { type Request, type Response } from \"express\";\r\nimport crypto from \"crypto\";\r\nimport { DEFAULT_IMAGE_CONFIG, optimizeImage } from \"../utils/image-optimizer\";\r\nimport type { ImageConfig } from \"../utils/image-validation\";\r\n\r\nexport interface ImageHandlerOptions {\r\n req: Request;\r\n res: Response;\r\n config?: ImageConfig;\r\n}\r\n\r\n/**\r\n * Handles image optimization requests.\r\n * Endpoint: /_loly/image?src=...&w=800&h=600&q=75&format=webp\r\n */\r\nexport async function handleImageRequest(options: ImageHandlerOptions): Promise<void> {\r\n const { req, res, config } = options;\r\n\r\n try {\r\n // Parse query parameters\r\n const src = req.query.src as string;\r\n const width = req.query.w ? parseInt(req.query.w as string, 10) : undefined;\r\n const height = req.query.h ? parseInt(req.query.h as string, 10) : undefined;\r\n const quality = req.query.q ? parseInt(req.query.q as string, 10) : undefined;\r\n const format = req.query.format as \"webp\" | \"avif\" | \"jpeg\" | \"png\" | \"auto\" | undefined;\r\n const fit = req.query.fit as \"contain\" | \"cover\" | \"fill\" | \"inside\" | \"outside\" | undefined;\r\n\r\n // Validate required parameters\r\n if (!src) {\r\n res.status(400).json({\r\n error: \"Missing required parameter: src\",\r\n });\r\n return;\r\n }\r\n\r\n // Validate src is a string\r\n if (typeof src !== \"string\") {\r\n res.status(400).json({\r\n error: \"Parameter 'src' must be a string\",\r\n });\r\n return;\r\n }\r\n\r\n // Generate ETag based on image parameters (images are immutable, so ETag = hash of params)\r\n // This allows the browser to revalidate without downloading the full image\r\n const etagInput = `${src}-${width || \"\"}-${height || \"\"}-${quality || \"\"}-${format || \"\"}-${fit || \"\"}`;\r\n const etag = `\"${crypto.createHash(\"md5\").update(etagInput).digest(\"hex\")}\"`;\r\n\r\n // Check if client has cached version (conditional request)\r\n const ifNoneMatch = req.headers[\"if-none-match\"];\r\n if (ifNoneMatch === etag) {\r\n // Resource hasn't changed, return 304 Not Modified\r\n res.status(304).end();\r\n return;\r\n }\r\n\r\n // Optimize image\r\n const result = await optimizeImage(\r\n {\r\n src,\r\n width,\r\n height,\r\n quality,\r\n format,\r\n fit,\r\n },\r\n config\r\n );\r\n\r\n // Set headers\r\n const imageConfig = config || {};\r\n const cacheTTL = imageConfig.minimumCacheTTL ?? DEFAULT_IMAGE_CONFIG.minimumCacheTTL;\r\n\r\n res.setHeader(\"Content-Type\", result.mimeType);\r\n res.setHeader(\"Content-Length\", result.buffer.length);\r\n res.setHeader(\"Cache-Control\", `public, max-age=${cacheTTL}, immutable`);\r\n res.setHeader(\"ETag\", etag);\r\n res.setHeader(\"X-Content-Type-Options\", \"nosniff\");\r\n\r\n // Send image\r\n res.send(result.buffer);\r\n } catch (error) {\r\n // Handle different error types\r\n if (error instanceof Error) {\r\n // Domain not allowed\r\n if (error.message.includes(\"not allowed\")) {\r\n res.status(403).json({\r\n error: \"Forbidden\",\r\n message: error.message,\r\n });\r\n return;\r\n }\r\n\r\n // Image not found\r\n if (error.message.includes(\"not found\") || error.message.includes(\"Image not found\")) {\r\n res.status(404).json({\r\n error: \"Not Found\",\r\n message: error.message,\r\n });\r\n return;\r\n }\r\n\r\n // Validation errors\r\n if (error.message.includes(\"must be\")) {\r\n res.status(400).json({\r\n error: \"Bad Request\",\r\n message: error.message,\r\n });\r\n return;\r\n }\r\n\r\n // Download/timeout errors\r\n if (error.message.includes(\"timeout\") || error.message.includes(\"download\")) {\r\n res.status(504).json({\r\n error: \"Gateway Timeout\",\r\n message: error.message,\r\n });\r\n return;\r\n }\r\n }\r\n\r\n // Generic server error\r\n console.error(\"[image-optimizer] Error processing image:\", error);\r\n res.status(500).json({\r\n error: \"Internal Server Error\",\r\n message: \"Failed to process image\",\r\n });\r\n }\r\n}\r\n\r\n","import sharp from \"sharp\";\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\nimport { getProjectDir, getPublicDir } from \"../../context\";\r\nimport {\r\n isRemoteUrl,\r\n validateRemoteUrl,\r\n sanitizeImagePath,\r\n validateImageDimensions,\r\n validateQuality,\r\n type ImageConfig,\r\n} from \"./image-validation\";\r\nimport {\r\n generateCacheKey,\r\n getCacheDir,\r\n hasCachedImage,\r\n readCachedImage,\r\n writeCachedImage,\r\n getImageExtension,\r\n getImageMimeType,\r\n getLRUCache,\r\n cleanupCache,\r\n} from \"./image-cache\";\r\n\r\nexport interface OptimizeImageOptions {\r\n src: string;\r\n width?: number;\r\n height?: number;\r\n quality?: number;\r\n format?: \"webp\" | \"avif\" | \"jpeg\" | \"png\" | \"auto\";\r\n fit?: \"contain\" | \"cover\" | \"fill\" | \"inside\" | \"outside\";\r\n}\r\n\r\nexport interface OptimizedImageResult {\r\n buffer: Buffer;\r\n format: string;\r\n mimeType: string;\r\n width: number;\r\n height: number;\r\n}\r\n\r\n/**\r\n * Default image configuration\r\n */\r\nexport const DEFAULT_IMAGE_CONFIG: ImageConfig = {\r\n maxWidth: 3840,\r\n maxHeight: 3840,\r\n quality: 70,\r\n formats: [\"image/avif\", \"image/webp\"],\r\n minimumCacheTTL: 31536000, // 1 año (en lugar de 60)\r\n cacheMaxSize: 500,\r\n cacheMaxAge: 30,\r\n cacheLRUSize: 50,\r\n cacheCleanupInterval: 100,\r\n};\r\n\r\n/**\r\n * Request counter for periodic cleanup\r\n */\r\nlet requestCount = 0;\r\n\r\n/**\r\n * Downloads a remote image with timeout.\r\n */\r\nasync function downloadRemoteImage(url: string, timeout: number = 10000): Promise<Buffer> {\r\n // Use native fetch (Node 18+)\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), timeout);\r\n\r\n try {\r\n const response = await fetch(url, {\r\n signal: controller.signal,\r\n headers: {\r\n \"User-Agent\": \"Loly-Image-Optimizer/1.0\",\r\n },\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to download image: ${response.status} ${response.statusText}`);\r\n }\r\n\r\n const arrayBuffer = await response.arrayBuffer();\r\n return Buffer.from(arrayBuffer);\r\n } catch (error) {\r\n clearTimeout(timeoutId);\r\n if (error instanceof Error && error.name === \"AbortError\") {\r\n throw new Error(`Image download timeout after ${timeout}ms`);\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Reads a local image file.\r\n */\r\nfunction readLocalImage(src: string, projectRoot: string): Buffer {\r\n // Sanitize path to prevent path traversal\r\n const sanitized = sanitizeImagePath(src);\r\n\r\n // Try public directory first\r\n const publicDir = getPublicDir();\r\n const publicPath = path.join(publicDir, sanitized);\r\n\r\n if (fs.existsSync(publicPath)) {\r\n return fs.readFileSync(publicPath);\r\n }\r\n\r\n // Try as absolute path (if src starts with /)\r\n if (src.startsWith(\"/\")) {\r\n const absolutePath = path.join(projectRoot, sanitized);\r\n if (fs.existsSync(absolutePath)) {\r\n return fs.readFileSync(absolutePath);\r\n }\r\n }\r\n\r\n throw new Error(`Image not found: ${src}`);\r\n}\r\n\r\n/**\r\n * Determines the best output format based on config and source format.\r\n */\r\nfunction determineOutputFormat(\r\n sourceFormat: string,\r\n requestedFormat: \"webp\" | \"avif\" | \"jpeg\" | \"png\" | \"auto\" | undefined,\r\n config: ImageConfig\r\n): string {\r\n // Handle SVG separately (will be checked later)\r\n if (sourceFormat === \"svg\") {\r\n return \"svg\";\r\n }\r\n\r\n if (requestedFormat && requestedFormat !== \"auto\") {\r\n return requestedFormat;\r\n }\r\n\r\n // Use first supported format from config (AVIF preferred for better compression)\r\n const supportedFormats = config.formats || [\"image/webp\"];\r\n \r\n // Prefer AVIF if supported (better compression than WebP)\r\n if (supportedFormats.includes(\"image/avif\")) {\r\n return \"avif\";\r\n }\r\n if (supportedFormats.includes(\"image/webp\")) {\r\n return \"webp\";\r\n }\r\n\r\n // Fallback to original format (but not SVG)\r\n return sourceFormat === \"svg\" ? \"jpeg\" : sourceFormat;\r\n}\r\n\r\n/**\r\n * Optimizes an image using Sharp.\r\n */\r\nexport async function optimizeImage(\r\n options: OptimizeImageOptions,\r\n config?: ImageConfig\r\n): Promise<OptimizedImageResult> {\r\n const imageConfig = config || DEFAULT_IMAGE_CONFIG;\r\n const projectRoot = getProjectDir();\r\n\r\n // Validate dimensions\r\n const dimValidation = validateImageDimensions(options.width, options.height, imageConfig);\r\n if (!dimValidation.valid) {\r\n throw new Error(dimValidation.error);\r\n }\r\n\r\n // Validate quality\r\n const qualityValidation = validateQuality(options.quality);\r\n if (!qualityValidation.valid) {\r\n throw new Error(qualityValidation.error);\r\n }\r\n\r\n // Validate remote URL if needed\r\n if (isRemoteUrl(options.src)) {\r\n if (!validateRemoteUrl(options.src, imageConfig)) {\r\n throw new Error(`Remote image domain not allowed: ${options.src}`);\r\n }\r\n }\r\n\r\n // Determine output format\r\n const sourceFormat = path.extname(options.src).slice(1).toLowerCase() || \"jpeg\";\r\n const outputFormat = determineOutputFormat(sourceFormat, options.format, imageConfig);\r\n\r\n // Generate cache key\r\n const cacheKey = generateCacheKey(\r\n options.src,\r\n options.width,\r\n options.height,\r\n options.quality || imageConfig.quality || 75,\r\n outputFormat\r\n );\r\n\r\n const cacheDir = getCacheDir();\r\n const extension = getImageExtension(outputFormat);\r\n const fullCacheKey = `${cacheKey}.${extension}`;\r\n\r\n // Initialize LRU cache with configuration\r\n const lruSize = imageConfig.cacheLRUSize || DEFAULT_IMAGE_CONFIG.cacheLRUSize || 50;\r\n const lruCache = getLRUCache(lruSize);\r\n\r\n // Check LRU cache first (fastest)\r\n const lruCached = lruCache.get(fullCacheKey);\r\n if (lruCached) {\r\n const metadata = await sharp(lruCached).metadata();\r\n return {\r\n buffer: lruCached,\r\n format: outputFormat,\r\n mimeType: getImageMimeType(outputFormat),\r\n width: metadata.width || options.width || 0,\r\n height: metadata.height || options.height || 0,\r\n };\r\n }\r\n\r\n // Check filesystem cache\r\n if (hasCachedImage(cacheKey, extension, cacheDir)) {\r\n const cached = readCachedImage(cacheKey, extension, cacheDir);\r\n if (cached) {\r\n // Load into LRU cache for faster future access\r\n lruCache.set(fullCacheKey, cached);\r\n\r\n // Get dimensions from cached image metadata\r\n const metadata = await sharp(cached).metadata();\r\n return {\r\n buffer: cached,\r\n format: outputFormat,\r\n mimeType: getImageMimeType(outputFormat),\r\n width: metadata.width || options.width || 0,\r\n height: metadata.height || options.height || 0,\r\n };\r\n }\r\n }\r\n\r\n // Load image\r\n let imageBuffer: Buffer;\r\n if (isRemoteUrl(options.src)) {\r\n imageBuffer = await downloadRemoteImage(options.src);\r\n } else {\r\n imageBuffer = readLocalImage(options.src, projectRoot);\r\n }\r\n\r\n // Handle SVG separately (Sharp doesn't process SVG)\r\n if (outputFormat === \"svg\" || sourceFormat === \"svg\") {\r\n if (!imageConfig.dangerouslyAllowSVG) {\r\n throw new Error(\"SVG images are not allowed. Set images.dangerouslyAllowSVG to true to enable.\");\r\n }\r\n // Return SVG as-is (no optimization)\r\n return {\r\n buffer: imageBuffer,\r\n format: \"svg\",\r\n mimeType: \"image/svg+xml\",\r\n width: options.width || 0,\r\n height: options.height || 0,\r\n };\r\n }\r\n\r\n // Process with Sharp\r\n let sharpInstance = sharp(imageBuffer);\r\n\r\n // Get metadata\r\n const metadata = await sharpInstance.metadata();\r\n\r\n // Resize if needed\r\n if (options.width || options.height) {\r\n const fit = options.fit || \"cover\";\r\n sharpInstance = sharpInstance.resize(options.width, options.height, {\r\n fit,\r\n withoutEnlargement: true,\r\n });\r\n }\r\n\r\n // Convert format and apply quality\r\n const quality = options.quality || imageConfig.quality || 75;\r\n\r\n switch (outputFormat) {\r\n case \"webp\":\r\n sharpInstance = sharpInstance.webp({ quality });\r\n break;\r\n case \"avif\":\r\n sharpInstance = sharpInstance.avif({ quality });\r\n break;\r\n case \"jpeg\":\r\n case \"jpg\":\r\n sharpInstance = sharpInstance.jpeg({ quality });\r\n break;\r\n case \"png\":\r\n sharpInstance = sharpInstance.png({ quality: Math.round(quality / 100 * 9) });\r\n break;\r\n default:\r\n sharpInstance = sharpInstance.jpeg({ quality });\r\n }\r\n\r\n // Generate optimized image\r\n const optimizedBuffer = await sharpInstance.toBuffer();\r\n\r\n // Get final dimensions\r\n const finalMetadata = await sharp(optimizedBuffer).metadata();\r\n\r\n // Cache the result in both LRU and filesystem\r\n lruCache.set(fullCacheKey, optimizedBuffer);\r\n writeCachedImage(cacheKey, extension, cacheDir, optimizedBuffer);\r\n\r\n // Periodic cleanup (non-blocking)\r\n requestCount++;\r\n const cleanupInterval = imageConfig.cacheCleanupInterval || DEFAULT_IMAGE_CONFIG.cacheCleanupInterval || 100;\r\n if (requestCount >= cleanupInterval) {\r\n requestCount = 0;\r\n // Run cleanup asynchronously to not block the request\r\n setImmediate(() => {\r\n try {\r\n const cleanupResult = cleanupCache({\r\n maxSizeMB: imageConfig.cacheMaxSize || DEFAULT_IMAGE_CONFIG.cacheMaxSize,\r\n maxAgeDays: imageConfig.cacheMaxAge || DEFAULT_IMAGE_CONFIG.cacheMaxAge,\r\n });\r\n if (cleanupResult.deleted > 0) {\r\n console.log(\r\n `[image-cache] Cleaned up ${cleanupResult.deleted} files, freed ${(cleanupResult.freed / 1024 / 1024).toFixed(2)} MB`\r\n );\r\n }\r\n } catch (error) {\r\n // Don't fail requests if cleanup fails\r\n console.warn(\"[image-cache] Cleanup failed:\", error);\r\n }\r\n });\r\n }\r\n\r\n return {\r\n buffer: optimizedBuffer,\r\n format: outputFormat,\r\n mimeType: getImageMimeType(outputFormat),\r\n width: finalMetadata.width || options.width || metadata.width || 0,\r\n height: finalMetadata.height || options.height || metadata.height || 0,\r\n };\r\n}\r\n\r\n","import path from \"path\";\r\n\r\n/**\r\n * Image configuration interface\r\n */\r\nexport interface ImageConfig {\r\n domains?: string[];\r\n remotePatterns?: RemotePattern[];\r\n maxWidth?: number;\r\n maxHeight?: number;\r\n quality?: number;\r\n formats?: string[];\r\n dangerouslyAllowSVG?: boolean;\r\n minimumCacheTTL?: number;\r\n // Cache configuration\r\n cacheMaxSize?: number; // Tamaño máximo del cache en MB (default: 500MB)\r\n cacheMaxAge?: number; // Días antes de considerar archivo antiguo (default: 30)\r\n cacheLRUSize?: number; // Número de imágenes en LRU (default: 50)\r\n cacheCleanupInterval?: number; // Requests antes de limpiar (default: 100)\r\n}\r\n\r\n/**\r\n * Remote pattern for image URL validation\r\n */\r\nexport interface RemotePattern {\r\n protocol?: \"http\" | \"https\";\r\n hostname: string;\r\n port?: string;\r\n pathname?: string;\r\n}\r\n\r\n/**\r\n * Checks if a URL is a remote URL (http/https).\r\n */\r\nexport function isRemoteUrl(url: string): boolean {\r\n return url.startsWith(\"http://\") || url.startsWith(\"https://\");\r\n}\r\n\r\n/**\r\n * Sanitizes an image path to prevent path traversal attacks.\r\n */\r\nexport function sanitizeImagePath(imagePath: string): string {\r\n // Remove any path traversal attempts\r\n const normalized = path.normalize(imagePath).replace(/^(\\.\\.(\\/|\\\\|$))+/, \"\");\r\n // Remove leading slashes and backslashes\r\n return normalized.replace(/^[/\\\\]+/, \"\");\r\n}\r\n\r\n/**\r\n * Converts a remote pattern to a regex for matching.\r\n */\r\nfunction patternToRegex(pattern: RemotePattern): RegExp {\r\n const parts: string[] = [];\r\n\r\n // Protocol\r\n if (pattern.protocol) {\r\n parts.push(pattern.protocol === \"https\" ? \"https\" : \"http\");\r\n } else {\r\n parts.push(\"https?\"); // Match both http and https\r\n }\r\n\r\n parts.push(\"://\");\r\n\r\n // Hostname - support wildcards\r\n let hostnamePattern = pattern.hostname\r\n .replace(/\\./g, \"\\\\.\")\r\n .replace(/\\*\\*/g, \".*\")\r\n .replace(/\\*/g, \"[^.]*\");\r\n parts.push(hostnamePattern);\r\n\r\n // Port\r\n if (pattern.port) {\r\n parts.push(`:${pattern.port}`);\r\n }\r\n\r\n // Pathname\r\n if (pattern.pathname) {\r\n let pathnamePattern = pattern.pathname\r\n .replace(/\\*\\*/g, \".*\")\r\n .replace(/\\*/g, \"[^/]*\");\r\n parts.push(pathnamePattern);\r\n } else {\r\n parts.push(\".*\"); // Match any pathname if not specified\r\n }\r\n\r\n const regexSource = `^${parts.join(\"\")}`;\r\n return new RegExp(regexSource);\r\n}\r\n\r\n/**\r\n * Validates if a remote URL matches any of the allowed patterns.\r\n * If no config is provided, allows all remote URLs (development mode).\r\n */\r\nexport function validateRemoteUrl(url: string, config?: ImageConfig): boolean {\r\n // If no config, allow all (development mode)\r\n if (!config || (!config.remotePatterns && !config.domains)) {\r\n return true;\r\n }\r\n\r\n try {\r\n const urlObj = new URL(url);\r\n const protocol = urlObj.protocol.replace(\":\", \"\") as \"http\" | \"https\";\r\n const hostname = urlObj.hostname;\r\n const port = urlObj.port || \"\";\r\n const pathname = urlObj.pathname;\r\n\r\n // Check remotePatterns first (more flexible)\r\n if (config.remotePatterns && config.remotePatterns.length > 0) {\r\n for (const pattern of config.remotePatterns) {\r\n const regex = patternToRegex(pattern);\r\n const testUrl = `${protocol}://${hostname}${port ? `:${port}` : \"\"}${pathname}`;\r\n\r\n if (regex.test(testUrl)) {\r\n // Additional checks\r\n if (pattern.protocol && pattern.protocol !== protocol) {\r\n continue;\r\n }\r\n if (pattern.port && pattern.port !== port) {\r\n continue;\r\n }\r\n\r\n return true;\r\n }\r\n }\r\n }\r\n\r\n // Fallback to legacy domains format\r\n if (config.domains && config.domains.length > 0) {\r\n for (const domain of config.domains) {\r\n // Support wildcards in domain\r\n const domainPattern = domain\r\n .replace(/\\./g, \"\\\\.\")\r\n .replace(/\\*\\*/g, \".*\")\r\n .replace(/\\*/g, \"[^.]*\");\r\n const regex = new RegExp(`^${domainPattern}$`);\r\n\r\n if (regex.test(hostname)) {\r\n // Only allow HTTPS in production for legacy domains (security best practice)\r\n if (process.env.NODE_ENV === \"production\" && protocol !== \"https\") {\r\n continue;\r\n }\r\n return true;\r\n }\r\n }\r\n }\r\n\r\n return false;\r\n } catch (error) {\r\n // Invalid URL\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Validates image dimensions against maximum allowed sizes.\r\n */\r\nexport function validateImageDimensions(\r\n width: number | undefined,\r\n height: number | undefined,\r\n config?: ImageConfig\r\n): { valid: boolean; error?: string } {\r\n const maxWidth = config?.maxWidth || 3840;\r\n const maxHeight = config?.maxHeight || 3840;\r\n\r\n if (width !== undefined && (width <= 0 || width > maxWidth)) {\r\n return {\r\n valid: false,\r\n error: `Image width must be between 1 and ${maxWidth}, got ${width}`,\r\n };\r\n }\r\n\r\n if (height !== undefined && (height <= 0 || height > maxHeight)) {\r\n return {\r\n valid: false,\r\n error: `Image height must be between 1 and ${maxHeight}, got ${height}`,\r\n };\r\n }\r\n\r\n return { valid: true };\r\n}\r\n\r\n/**\r\n * Validates image quality parameter.\r\n */\r\nexport function validateQuality(quality: number | undefined): { valid: boolean; error?: string } {\r\n if (quality === undefined) {\r\n return { valid: true };\r\n }\r\n\r\n if (typeof quality !== \"number\" || quality < 1 || quality > 100) {\r\n return {\r\n valid: false,\r\n error: `Image quality must be between 1 and 100, got ${quality}`,\r\n };\r\n }\r\n\r\n return { valid: true };\r\n}\r\n\r\n","import fs from \"fs\";\r\nimport path from \"path\";\r\nimport crypto from \"crypto\";\r\nimport { getProjectDir } from \"../../context\";\r\nimport { DIRECTORIES } from \"../../constants/directories\";\r\n\r\n/**\r\n * LRU Cache implementation for in-memory image caching\r\n * Maintains access order using Map's insertion order\r\n */\r\nexport class ImageLRUCache {\r\n private cache: Map<string, Buffer>;\r\n private readonly maxSize: number;\r\n\r\n constructor(maxSize: number = 50) {\r\n this.maxSize = maxSize;\r\n this.cache = new Map();\r\n }\r\n\r\n /**\r\n * Get an image from cache\r\n */\r\n get(key: string): Buffer | undefined {\r\n if (!this.cache.has(key)) {\r\n return undefined;\r\n }\r\n\r\n // Move to end (most recently used)\r\n const value = this.cache.get(key)!;\r\n this.cache.delete(key);\r\n this.cache.set(key, value);\r\n return value;\r\n }\r\n\r\n /**\r\n * Set an image in cache\r\n */\r\n set(key: string, value: Buffer): void {\r\n if (this.cache.has(key)) {\r\n // Update existing: remove and re-add to end\r\n this.cache.delete(key);\r\n } else if (this.cache.size >= this.maxSize) {\r\n // Evict least recently used (first item)\r\n const firstKey = this.cache.keys().next().value;\r\n\r\n if (firstKey) {\r\n this.cache.delete(firstKey);\r\n }\r\n }\r\n this.cache.set(key, value);\r\n }\r\n\r\n /**\r\n * Check if key exists in cache\r\n */\r\n has(key: string): boolean {\r\n return this.cache.has(key);\r\n }\r\n\r\n /**\r\n * Clear the cache\r\n */\r\n clear(): void {\r\n this.cache.clear();\r\n }\r\n\r\n /**\r\n * Get cache size\r\n */\r\n size(): number {\r\n return this.cache.size;\r\n }\r\n}\r\n\r\n/**\r\n * Global LRU cache instance (singleton pattern)\r\n */\r\nlet globalLRUCache: ImageLRUCache | null = null;\r\n\r\n/**\r\n * Get or create the global LRU cache instance\r\n */\r\nexport function getLRUCache(maxSize?: number): ImageLRUCache {\r\n if (!globalLRUCache) {\r\n globalLRUCache = new ImageLRUCache(maxSize);\r\n }\r\n return globalLRUCache;\r\n}\r\n\r\n/**\r\n * Reset the global LRU cache (useful for testing)\r\n */\r\nexport function resetLRUCache(): void {\r\n globalLRUCache = null;\r\n}\r\n\r\n/**\r\n * Generates a hash for cache key based on image source and optimization parameters.\r\n */\r\nexport function generateCacheKey(\r\n src: string,\r\n width?: number,\r\n height?: number,\r\n quality?: number,\r\n format?: string\r\n): string {\r\n const data = `${src}-${width || \"\"}-${height || \"\"}-${quality || \"\"}-${format || \"\"}`;\r\n return crypto.createHash(\"sha256\").update(data).digest(\"hex\");\r\n}\r\n\r\n/**\r\n * Gets the cache directory path for optimized images.\r\n */\r\nexport function getCacheDir(): string {\r\n const projectDir = getProjectDir();\r\n return path.join(projectDir, DIRECTORIES.LOLY, \"cache\", \"images\");\r\n}\r\n\r\n/**\r\n * Ensures the cache directory exists.\r\n */\r\nexport function ensureCacheDir(cacheDir: string): void {\r\n if (!fs.existsSync(cacheDir)) {\r\n fs.mkdirSync(cacheDir, { recursive: true });\r\n }\r\n}\r\n\r\n/**\r\n * Gets the cached image file path if it exists.\r\n */\r\nexport function getCachedImagePath(\r\n cacheKey: string,\r\n extension: string,\r\n cacheDir: string\r\n): string {\r\n return path.join(cacheDir, `${cacheKey}.${extension}`);\r\n}\r\n\r\n/**\r\n * Checks if a cached image exists.\r\n */\r\nexport function hasCachedImage(\r\n cacheKey: string,\r\n extension: string,\r\n cacheDir: string\r\n): boolean {\r\n const cachedPath = getCachedImagePath(cacheKey, extension, cacheDir);\r\n return fs.existsSync(cachedPath);\r\n}\r\n\r\n/**\r\n * Reads a cached image from disk.\r\n */\r\nexport function readCachedImage(\r\n cacheKey: string,\r\n extension: string,\r\n cacheDir: string\r\n): Buffer | null {\r\n const cachedPath = getCachedImagePath(cacheKey, extension, cacheDir);\r\n\r\n try {\r\n if (fs.existsSync(cachedPath)) {\r\n return fs.readFileSync(cachedPath);\r\n }\r\n } catch (error) {\r\n // If read fails, return null (cache miss)\r\n console.warn(`[image-optimizer] Failed to read cached image: ${cachedPath}`, error);\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Writes an optimized image to cache.\r\n */\r\nexport function writeCachedImage(\r\n cacheKey: string,\r\n extension: string,\r\n cacheDir: string,\r\n imageBuffer: Buffer\r\n): void {\r\n ensureCacheDir(cacheDir);\r\n const cachedPath = getCachedImagePath(cacheKey, extension, cacheDir);\r\n\r\n try {\r\n fs.writeFileSync(cachedPath, imageBuffer);\r\n } catch (error) {\r\n console.warn(`[image-optimizer] Failed to write cached image: ${cachedPath}`, error);\r\n }\r\n}\r\n\r\n/**\r\n * Gets the MIME type for a given image format/extension.\r\n */\r\nexport function getImageMimeType(format: string): string {\r\n const formatMap: Record<string, string> = {\r\n webp: \"image/webp\",\r\n avif: \"image/avif\",\r\n jpeg: \"image/jpeg\",\r\n jpg: \"image/jpeg\",\r\n png: \"image/png\",\r\n gif: \"image/gif\",\r\n svg: \"image/svg+xml\",\r\n };\r\n\r\n const normalized = format.toLowerCase();\r\n return formatMap[normalized] || \"image/jpeg\";\r\n}\r\n\r\n/**\r\n * Gets the file extension from a MIME type or format string.\r\n */\r\nexport function getImageExtension(format: string): string {\r\n const formatMap: Record<string, string> = {\r\n \"image/webp\": \"webp\",\r\n \"image/avif\": \"avif\",\r\n \"image/jpeg\": \"jpg\",\r\n \"image/png\": \"png\",\r\n \"image/gif\": \"gif\",\r\n \"image/svg+xml\": \"svg\",\r\n webp: \"webp\",\r\n avif: \"avif\",\r\n jpeg: \"jpg\",\r\n jpg: \"jpg\",\r\n png: \"png\",\r\n gif: \"gif\",\r\n svg: \"svg\",\r\n };\r\n\r\n const normalized = format.toLowerCase();\r\n return formatMap[normalized] || \"jpg\";\r\n}\r\n\r\n/**\r\n * Cache statistics interface\r\n */\r\nexport interface CacheStats {\r\n totalFiles: number;\r\n totalSize: number; // in bytes\r\n oldestFile?: Date;\r\n newestFile?: Date;\r\n}\r\n\r\n/**\r\n * Get cache statistics\r\n */\r\nexport function getCacheStats(cacheDir: string): CacheStats {\r\n const stats: CacheStats = {\r\n totalFiles: 0,\r\n totalSize: 0,\r\n };\r\n\r\n try {\r\n if (!fs.existsSync(cacheDir)) {\r\n return stats;\r\n }\r\n\r\n const files = fs.readdirSync(cacheDir);\r\n let oldestTime: number | undefined;\r\n let newestTime: number | undefined;\r\n\r\n for (const file of files) {\r\n const filePath = path.join(cacheDir, file);\r\n try {\r\n const stat = fs.statSync(filePath);\r\n if (stat.isFile()) {\r\n stats.totalFiles++;\r\n stats.totalSize += stat.size;\r\n\r\n const mtime = stat.mtime.getTime();\r\n if (oldestTime === undefined || mtime < oldestTime) {\r\n oldestTime = mtime;\r\n stats.oldestFile = stat.mtime;\r\n }\r\n if (newestTime === undefined || mtime > newestTime) {\r\n newestTime = mtime;\r\n stats.newestFile = stat.mtime;\r\n }\r\n }\r\n } catch (error) {\r\n // Skip files that can't be read\r\n continue;\r\n }\r\n }\r\n } catch (error) {\r\n console.warn(`[image-cache] Failed to get cache stats: ${cacheDir}`, error);\r\n }\r\n\r\n return stats;\r\n}\r\n\r\n/**\r\n * Get total cache size in bytes\r\n */\r\nexport function getCacheSize(cacheDir: string): number {\r\n return getCacheStats(cacheDir).totalSize;\r\n}\r\n\r\n/**\r\n * Cleanup cache by age - removes files older than maxAge days\r\n */\r\nexport function cleanupCacheByAge(\r\n cacheDir: string,\r\n maxAgeDays: number = 30\r\n): { deleted: number; freed: number } {\r\n const result = { deleted: 0, freed: 0 };\r\n const maxAgeMs = maxAgeDays * 24 * 60 * 60 * 1000;\r\n const now = Date.now();\r\n\r\n try {\r\n if (!fs.existsSync(cacheDir)) {\r\n return result;\r\n }\r\n\r\n const files = fs.readdirSync(cacheDir);\r\n\r\n for (const file of files) {\r\n const filePath = path.join(cacheDir, file);\r\n try {\r\n const stat = fs.statSync(filePath);\r\n if (stat.isFile()) {\r\n const age = now - stat.mtime.getTime();\r\n if (age > maxAgeMs) {\r\n const size = stat.size;\r\n fs.unlinkSync(filePath);\r\n result.deleted++;\r\n result.freed += size;\r\n }\r\n }\r\n } catch (error) {\r\n // Skip files that can't be read/deleted\r\n continue;\r\n }\r\n }\r\n } catch (error) {\r\n console.warn(`[image-cache] Failed to cleanup cache by age: ${cacheDir}`, error);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Cleanup cache by size - removes oldest files when cache exceeds maxSizeMB\r\n */\r\nexport function cleanupCacheBySize(\r\n cacheDir: string,\r\n maxSizeMB: number = 500\r\n): { deleted: number; freed: number } {\r\n const result = { deleted: 0, freed: 0 };\r\n const maxSizeBytes = maxSizeMB * 1024 * 1024;\r\n\r\n try {\r\n if (!fs.existsSync(cacheDir)) {\r\n return result;\r\n }\r\n\r\n const files = fs.readdirSync(cacheDir);\r\n const fileInfos: Array<{ path: string; mtime: number; size: number }> = [];\r\n\r\n // Collect file information\r\n for (const file of files) {\r\n const filePath = path.join(cacheDir, file);\r\n try {\r\n const stat = fs.statSync(filePath);\r\n if (stat.isFile()) {\r\n fileInfos.push({\r\n path: filePath,\r\n mtime: stat.mtime.getTime(),\r\n size: stat.size,\r\n });\r\n }\r\n } catch (error) {\r\n continue;\r\n }\r\n }\r\n\r\n // Calculate total size\r\n const totalSize = fileInfos.reduce((sum, info) => sum + info.size, 0);\r\n\r\n // If under limit, no cleanup needed\r\n if (totalSize <= maxSizeBytes) {\r\n return result;\r\n }\r\n\r\n // Sort by modification time (oldest first)\r\n fileInfos.sort((a, b) => a.mtime - b.mtime);\r\n\r\n // Delete oldest files until under limit\r\n let currentSize = totalSize;\r\n for (const fileInfo of fileInfos) {\r\n if (currentSize <= maxSizeBytes) {\r\n break;\r\n }\r\n\r\n try {\r\n fs.unlinkSync(fileInfo.path);\r\n result.deleted++;\r\n result.freed += fileInfo.size;\r\n currentSize -= fileInfo.size;\r\n } catch (error) {\r\n // Skip files that can't be deleted\r\n continue;\r\n }\r\n }\r\n } catch (error) {\r\n console.warn(`[image-cache] Failed to cleanup cache by size: ${cacheDir}`, error);\r\n }\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * Perform cache cleanup based on configuration\r\n */\r\nexport function cleanupCache(config?: {\r\n maxSizeMB?: number;\r\n maxAgeDays?: number;\r\n}): { deleted: number; freed: number } {\r\n const cacheDir = getCacheDir();\r\n const maxSizeMB = config?.maxSizeMB ?? 500;\r\n const maxAgeDays = config?.maxAgeDays ?? 30;\r\n\r\n // First cleanup by age\r\n const ageResult = cleanupCacheByAge(cacheDir, maxAgeDays);\r\n\r\n // Then cleanup by size if still needed\r\n const sizeResult = cleanupCacheBySize(cacheDir, maxSizeMB);\r\n\r\n return {\r\n deleted: ageResult.deleted + sizeResult.deleted,\r\n freed: ageResult.freed + sizeResult.freed,\r\n };\r\n}\r\n\r\n","import type { RouteConfig, RouteFile } from \"./types\";\r\nimport { normalizeUrlPath } from \"../utils/path\";\r\n\r\n/**\r\n * Match route pattern and extract params (shared logic)\r\n */\r\nfunction matchRoutePattern(\r\n pathname: string,\r\n route: RouteFile\r\n): { params: Record<string, string> } | null {\r\n const pathSegments = pathname === \"/\" ? [\"\"] : pathname.split(\"/\").filter(Boolean);\r\n const routeSegments = route.segments.filter((s) => !s.isOptional);\r\n\r\n if (routeSegments.length === 0 && pathSegments.length === 1 && pathSegments[0] === \"\") {\r\n return { params: {} }; // Root route\r\n }\r\n\r\n const params: Record<string, string> = {};\r\n let pathIdx = 0;\r\n let routeIdx = 0;\r\n\r\n while (pathIdx < pathSegments.length && routeIdx < routeSegments.length) {\r\n const routeSeg = routeSegments[routeIdx];\r\n const pathSeg = pathSegments[pathIdx];\r\n\r\n if (routeSeg.isCatchAll) {\r\n // Catch-all consumes everything remaining\r\n const remaining = pathSegments.slice(pathIdx);\r\n if (routeSeg.paramName) {\r\n params[routeSeg.paramName] = remaining.join(\"/\");\r\n }\r\n return { params };\r\n }\r\n\r\n if (routeSeg.isDynamic) {\r\n // Dynamic segment matches any value\r\n if (routeSeg.paramName) {\r\n params[routeSeg.paramName] = decodeURIComponent(pathSeg);\r\n }\r\n pathIdx++;\r\n routeIdx++;\r\n continue;\r\n }\r\n\r\n if (routeSeg.segment === pathSeg) {\r\n // Exact match\r\n pathIdx++;\r\n routeIdx++;\r\n continue;\r\n }\r\n\r\n return null;\r\n }\r\n\r\n if (pathIdx === pathSegments.length && routeIdx === routeSegments.length) {\r\n return { params };\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Match a URL pathname to an API route\r\n */\r\nexport function matchApiRoute(\r\n pathname: string,\r\n config: RouteConfig\r\n): { route: RouteFile; params: Record<string, string> } | null {\r\n // Normalize pathname\r\n const normalized = normalizeUrlPath(pathname);\r\n\r\n // Try exact match first in apiRouteMap\r\n if (config.apiRouteMap && config.apiRouteMap.has(normalized)) {\r\n const route = config.apiRouteMap.get(normalized)!;\r\n return { route, params: {} };\r\n }\r\n\r\n // Try pattern matching for API routes\r\n if (config.apiRouteMap) {\r\n for (const route of config.apiRouteMap.values()) {\r\n const match = matchRoutePattern(normalized, route);\r\n if (match) {\r\n return { route, params: match.params };\r\n }\r\n }\r\n }\r\n\r\n // Fallback: search in routes array for API routes\r\n for (const route of config.routes) {\r\n if (!route.isApiRoute || !route.urlPath) continue;\r\n\r\n const match = matchRoutePattern(normalized, route);\r\n if (match) {\r\n return { route, params: match.params };\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\n","import type { RouteFile } from \"../router/types\";\r\nimport { loadModule } from \"./module-loader\";\r\n\r\n/**\r\n * Valid HTTP methods for API routes\r\n */\r\nconst HTTP_METHODS = [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\", \"HEAD\", \"OPTIONS\"];\r\n\r\n/**\r\n * API route handler function signature\r\n */\r\nexport type ApiRouteHandler = (req: any, res: any) => Promise<any> | any;\r\n\r\n/**\r\n * Loaded API route module with available handlers\r\n */\r\nexport interface LoadedApiRoute {\r\n handlers: Map<string, ApiRouteHandler>;\r\n}\r\n\r\n/**\r\n * Load an API route module and extract HTTP method handlers\r\n * @param route - Route file information\r\n * @param compiledPath - Optional compiled path for production\r\n * @returns Loaded API route with available handlers\r\n */\r\nexport async function loadApiRoute(\r\n route: RouteFile,\r\n compiledPath?: string\r\n): Promise<LoadedApiRoute> {\r\n if (!route.isApiRoute) {\r\n throw new Error(`[loly-core] Route ${route.filePath} is not an API route`);\r\n }\r\n\r\n const sourcePath = route.filePath;\r\n const module = await loadModule(sourcePath, compiledPath);\r\n const handlers = new Map<string, ApiRouteHandler>();\r\n\r\n // Extract HTTP method handlers from module exports\r\n for (const exportName of Object.keys(module)) {\r\n const upperExport = exportName.toUpperCase();\r\n if (HTTP_METHODS.includes(upperExport) && typeof module[exportName] === \"function\") {\r\n handlers.set(upperExport, module[exportName]);\r\n }\r\n }\r\n\r\n if (handlers.size === 0) {\r\n throw new Error(\r\n `[loly-core] No valid HTTP method handlers found in API route ${route.filePath}`\r\n );\r\n }\r\n\r\n return { handlers };\r\n}\r\n\r\n/**\r\n * Check if a specific HTTP method is available in the route\r\n */\r\nexport function hasMethod(loadedRoute: LoadedApiRoute, method: string): boolean {\r\n return loadedRoute.handlers.has(method.toUpperCase());\r\n}\r\n\r\n/**\r\n * Get handler for a specific HTTP method\r\n */\r\nexport function getHandler(\r\n loadedRoute: LoadedApiRoute,\r\n method: string\r\n): ApiRouteHandler | undefined {\r\n return loadedRoute.handlers.get(method.toUpperCase());\r\n}\r\n\r\n","import type { Request, Response } from \"express\";\r\nimport type { RouteFile, RouteConfig } from \"../../router/types\";\r\nimport { matchApiRoute } from \"../../router/api-matcher\";\r\nimport { loadApiRoute, getHandler, hasMethod } from \"../../utils/api-route-loader\";\r\nimport { extractParams } from \"../../router/matcher\";\r\nimport { HTTP_STATUS } from \"../../constants\";\r\n\r\n/**\r\n * Handler for API route requests\r\n * Returns true if the route was matched and handled, false otherwise\r\n */\r\nexport type ApiRouteHandler = (\r\n pathname: string,\r\n method: string,\r\n req: Request,\r\n res: Response,\r\n config: RouteConfig\r\n) => Promise<boolean>;\r\n\r\n/**\r\n * Create an API route handler function\r\n */\r\nexport function createApiRouteHandler(): ApiRouteHandler {\r\n return async (\r\n pathname: string,\r\n method: string,\r\n req: Request,\r\n res: Response,\r\n config: RouteConfig\r\n ): Promise<boolean> => {\r\n try {\r\n // Match the API route\r\n const match = matchApiRoute(pathname, config);\r\n if (!match) {\r\n // Route not found - let SSR handle it\r\n return false;\r\n }\r\n\r\n const { route, params } = match;\r\n\r\n // Load the API route module\r\n const loadedRoute = await loadApiRoute(route);\r\n\r\n // Check if method is supported\r\n const upperMethod = method.toUpperCase();\r\n if (!hasMethod(loadedRoute, upperMethod)) {\r\n res\r\n .status(HTTP_STATUS.METHOD_NOT_ALLOWED)\r\n .json({ error: `Method ${method} not allowed` });\r\n return true; // Route matched, but method not allowed\r\n }\r\n\r\n // Get the handler for the method\r\n const handler = getHandler(loadedRoute, upperMethod);\r\n if (!handler) {\r\n res\r\n .status(HTTP_STATUS.METHOD_NOT_ALLOWED)\r\n .json({ error: `Method ${method} not allowed` });\r\n return true; // Route matched, but method not allowed\r\n }\r\n\r\n // Set route params in req.params (Express expects this)\r\n req.params = params;\r\n\r\n // Execute the handler\r\n await handler(req, res);\r\n return true; // Route matched and handled\r\n } catch (error) {\r\n console.error(\"[loly-core] Error handling API route:\", error);\r\n if (!res.headersSent) {\r\n res.status(HTTP_STATUS.INTERNAL_ERROR).json({\r\n error: \"Internal Server Error\",\r\n message: error instanceof Error ? error.message : String(error),\r\n });\r\n return true; // Error handled\r\n }\r\n return false; // Error occurred but response already sent\r\n }\r\n };\r\n}\r\n\r\n","import type { Request, Response } from \"express\";\r\nimport { HTTP_STATUS, SERVER } from \"../../constants\";\r\nimport { resolveAsyncTask } from \"../async-registry\";\r\nimport { renderToString } from \"loly-jsx\";\r\n\r\n/**\r\n * Handler for async component endpoint\r\n * GET /__loly/async/:id\r\n */\r\nexport async function handleAsyncRequest(req: Request, res: Response): Promise<void> {\r\n try {\r\n const asyncId = req.params.id;\r\n if (!asyncId) {\r\n res.status(HTTP_STATUS.BAD_REQUEST).json({\r\n html: null,\r\n error: \"Missing async ID\",\r\n });\r\n return;\r\n }\r\n\r\n // Resolve async task with timeout\r\n const timeoutPromise = new Promise<never>((_, reject) => {\r\n setTimeout(() => reject(new Error(\"Timeout\")), 30000); // 30 seconds\r\n });\r\n\r\n try {\r\n const resolvedVNode = await Promise.race([resolveAsyncTask(asyncId), timeoutPromise]);\r\n \r\n // Render VNode to HTML string\r\n const html = await renderToString(resolvedVNode);\r\n\r\n res.status(HTTP_STATUS.OK).json({\r\n html,\r\n error: null,\r\n });\r\n } catch (error) {\r\n if (error instanceof Error && error.message === \"Timeout\") {\r\n res.status(HTTP_STATUS.REQUEST_TIMEOUT).json({\r\n html: null,\r\n error: \"Async task timeout\",\r\n });\r\n return;\r\n }\r\n\r\n // Task not found or error resolving\r\n if (error instanceof Error && error.message.includes(\"not found\")) {\r\n res.status(HTTP_STATUS.NOT_FOUND).json({\r\n html: null,\r\n error: error.message,\r\n });\r\n return;\r\n }\r\n\r\n // Other error\r\n console.error(\"[loly] Error resolving async task:\", error);\r\n res.status(HTTP_STATUS.INTERNAL_ERROR).json({\r\n html: null,\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n }\r\n } catch (error) {\r\n console.error(\"[loly] Error handling async request:\", error);\r\n res.status(HTTP_STATUS.INTERNAL_ERROR).json({\r\n html: null,\r\n error: error instanceof Error ? error.message : \"Unknown error\",\r\n });\r\n }\r\n}\r\n\r\n","import { join } from \"path\";\r\nimport { existsSync, readFileSync } from \"fs\";\r\nimport type { RouteConfig } from \"../router/types\";\r\nimport { renderPageStream, renderPageContent } from \"./ssr\";\r\nimport {\r\n setContext,\r\n getAppDirPath,\r\n getRoutesManifestPath,\r\n getAppDir,\r\n setRouteConfig,\r\n} from \"../context\";\r\nimport { BaseServer } from \"./base-server\";\r\nimport { SERVER, ERROR_MESSAGES, DIRECTORIES } from \"../constants\";\r\nimport type { RSCHandler, SSRHandler } from \"../utils/express-setup\";\r\n\r\nexport interface ProdServerOptions {\r\n projectDir: string;\r\n port?: number;\r\n}\r\n\r\nimport type { RouteConfigWithManifest, ManifestRouteEntry } from \"../router/manifest-types\";\r\n\r\n/**\r\n * Load route configuration from manifest\r\n */\r\nfunction loadRouteConfigFromManifest(): RouteConfig & RouteConfigWithManifest {\r\n const manifestPath = getRoutesManifestPath();\r\n\r\n if (!existsSync(manifestPath)) {\r\n throw new Error(ERROR_MESSAGES.ROUTES_MANIFEST_NOT_FOUND(manifestPath));\r\n }\r\n\r\n const manifestContent = readFileSync(manifestPath, \"utf-8\");\r\n const manifest = JSON.parse(manifestContent);\r\n\r\n // Reconstruct RouteConfig from manifest\r\n // Use serverPath (compiled) if available, fallback to sourcePath\r\n const routes = manifest.routes.map((route: ManifestRouteEntry) => ({\r\n filePath: route.serverPath || route.sourcePath, // Prefer compiled path\r\n segments: route.segments,\r\n type: route.type,\r\n isRootLayout: route.isRootLayout,\r\n urlPath: route.urlPath,\r\n isApiRoute: route.isApiRoute || undefined,\r\n httpMethods: route.httpMethods || undefined,\r\n }));\r\n\r\n const rootLayout = manifest.rootLayout\r\n ? {\r\n filePath:\r\n manifest.rootLayout.serverPath || manifest.rootLayout.sourcePath,\r\n segments: manifest.rootLayout.segments,\r\n type: manifest.rootLayout.type,\r\n isRootLayout: manifest.rootLayout.isRootLayout,\r\n urlPath: manifest.rootLayout.urlPath,\r\n }\r\n : undefined;\r\n\r\n // Reconstruct routeMap and apiRouteMap\r\n const routeMap = new Map();\r\n const apiRouteMap = new Map();\r\n for (const routeEntry of manifest.routeMap || []) {\r\n const route = {\r\n filePath: routeEntry.serverPath || routeEntry.sourcePath,\r\n segments: routeEntry.segments,\r\n type: routeEntry.type,\r\n isRootLayout: routeEntry.isRootLayout,\r\n urlPath: routeEntry.urlPath,\r\n isApiRoute: routeEntry.isApiRoute || undefined,\r\n httpMethods: routeEntry.httpMethods || undefined,\r\n };\r\n if (routeEntry.type === \"page\") {\r\n routeMap.set(routeEntry.path, route);\r\n } else if (routeEntry.isApiRoute && routeEntry.urlPath) {\r\n apiRouteMap.set(routeEntry.urlPath, route);\r\n }\r\n }\r\n\r\n // Create routeMapManifest for accessing manifest data (including clientChunks)\r\n const routeMapManifest = new Map();\r\n for (const routeEntry of manifest.routeMap || []) {\r\n routeMapManifest.set(routeEntry.path, routeEntry);\r\n }\r\n\r\n return {\r\n routes,\r\n rootLayout,\r\n routeMap,\r\n apiRouteMap,\r\n routeMapManifest, // Include manifest data for accessing compiled paths and chunks\r\n rootLayoutManifest: manifest.rootLayout, // Include root layout manifest\r\n routesManifest: manifest.routes, // Include all routes from manifest for layout lookup\r\n };\r\n}\r\n\r\n/**\r\n * Production server class\r\n * Extends BaseServer with manifest-based route loading\r\n */\r\nexport class ProdServer extends BaseServer {\r\n private projectDir: string;\r\n private config: RouteConfig | null = null;\r\n\r\n constructor(options: ProdServerOptions) {\r\n super(options.port);\r\n this.projectDir = options.projectDir;\r\n }\r\n\r\n /**\r\n * Initialize server context and load routes from manifest\r\n */\r\n async initialize(): Promise<void> {\r\n const appDir = getAppDirPath(this.projectDir);\r\n const srcDir = join(this.projectDir, DIRECTORIES.SRC);\r\n const outDir = join(this.projectDir, DIRECTORIES.LOLY, DIRECTORIES.DIST);\r\n\r\n if (!existsSync(appDir)) {\r\n throw new Error(ERROR_MESSAGES.APP_DIR_NOT_FOUND(this.projectDir));\r\n }\r\n\r\n // Initialize context\r\n setContext({\r\n projectDir: this.projectDir,\r\n appDir,\r\n srcDir,\r\n outDir,\r\n buildMode: \"production\",\r\n isDev: false,\r\n serverPort: this.port,\r\n });\r\n\r\n // Load route configuration from manifest\r\n this.config = loadRouteConfigFromManifest();\r\n setRouteConfig(this.config);\r\n }\r\n\r\n /**\r\n * Create RSC handler\r\n */\r\n protected createRSCHandler(): RSCHandler {\r\n return async (pathname, searchParams) => {\r\n if (!this.config) {\r\n this.config = await this.loadRouteConfig();\r\n }\r\n const context = {\r\n pathname,\r\n searchParams,\r\n params: {} as Record<string, string>,\r\n };\r\n\r\n const result = await renderPageContent(context, this.config, getAppDir());\r\n return {\r\n ...result,\r\n params: context.params,\r\n };\r\n };\r\n }\r\n\r\n /**\r\n * Create SSR handler\r\n */\r\n protected createSSRHandler(): SSRHandler {\r\n return async (pathname, searchParams) => {\r\n if (!this.config) {\r\n this.config = await this.loadRouteConfig();\r\n }\r\n const context = {\r\n pathname,\r\n searchParams,\r\n params: {} as Record<string, string>,\r\n };\r\n return await renderPageStream(context, this.config, getAppDir());\r\n };\r\n }\r\n\r\n /**\r\n * Load route configuration from manifest\r\n */\r\n protected async loadRouteConfig(): Promise<RouteConfig> {\r\n return loadRouteConfigFromManifest();\r\n }\r\n\r\n /**\r\n * Start the production server\r\n */\r\n async start(): Promise<void> {\r\n await this.initialize();\r\n await this.setup();\r\n\r\n this.getApp().listen(this.port, () => {\r\n console.log(\r\n `[loly-core] Production server running at http://localhost:${this.port}`\r\n );\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * Convenience function to start production server\r\n * Maintains backward compatibility\r\n */\r\nexport async function startProdServer(\r\n options: ProdServerOptions\r\n): Promise<void> {\r\n const server = new ProdServer(options);\r\n await server.start();\r\n}\r\n\r\n","import type { ClientRouteLoaded } from \"./types\";\r\nimport { bootIslands, mount, activateAsyncComponents } from \"loly-jsx\";\r\nimport { SERVER } from \"../constants\";\r\nimport { matchesRoute, extractRouteParams } from \"../utils/route-matcher\";\r\nimport { normalizeUrlPath } from \"../utils/path\";\r\nimport { ERROR_MESSAGES } from \"../constants/errors\";\r\n\r\ninterface LocationState {\r\n pathname: string;\r\n search: string;\r\n hash: string;\r\n}\r\n\r\ntype RSCPayload = {\r\n html: string;\r\n scripts: string;\r\n styles: string;\r\n islandData?: Record<string, any>;\r\n};\r\n\r\n/**\r\n * LRU Cache implementation with configurable size limit\r\n * Maintains access order using Map's insertion order\r\n */\r\nclass LRUCache<K, V> {\r\n private cache: Map<K, V>;\r\n private readonly maxSize: number;\r\n\r\n constructor(maxSize: number = 10) {\r\n this.maxSize = maxSize;\r\n this.cache = new Map();\r\n }\r\n\r\n get(key: K): V | undefined {\r\n if (!this.cache.has(key)) {\r\n return undefined;\r\n }\r\n\r\n // Move to end (most recently used)\r\n const value = this.cache.get(key)!;\r\n this.cache.delete(key);\r\n this.cache.set(key, value);\r\n return value;\r\n }\r\n\r\n set(key: K, value: V): void {\r\n if (this.cache.has(key)) {\r\n // Update existing: remove and re-add to end\r\n this.cache.delete(key);\r\n } else if (this.cache.size >= this.maxSize) {\r\n // Remove oldest (first entry)\r\n const firstKey = this.cache.keys().next().value;\r\n if (firstKey !== undefined) {\r\n this.cache.delete(firstKey);\r\n }\r\n }\r\n\r\n this.cache.set(key, value);\r\n }\r\n\r\n has(key: K): boolean {\r\n return this.cache.has(key);\r\n }\r\n\r\n delete(key: K): boolean {\r\n return this.cache.delete(key);\r\n }\r\n\r\n clear(): void {\r\n this.cache.clear();\r\n }\r\n\r\n get size(): number {\r\n return this.cache.size;\r\n }\r\n}\r\n\r\nfunction getInitialLocation(): LocationState {\r\n const { pathname, search, hash } = window.location;\r\n return { pathname, search, hash };\r\n}\r\n\r\nfunction normalizePath(path: string): LocationState {\r\n const url = new URL(path, \"http://localhost\");\r\n return {\r\n pathname: normalizeUrlPath(url.pathname || \"/\"),\r\n search: url.search,\r\n hash: url.hash,\r\n };\r\n}\r\n\r\n/**\r\n * Fetch RSC payload from server\r\n */\r\nasync function fetchRSCPayload(\r\n pathname: string,\r\n search: string = \"\",\r\n options?: { priority?: RequestPriority }\r\n): Promise<RSCPayload | null> {\r\n const url = `${SERVER.RSC_ENDPOINT}?path=${encodeURIComponent(pathname)}${\r\n search ? `&search=${encodeURIComponent(search)}` : \"\"\r\n }`;\r\n\r\n try {\r\n const fetchOptions: RequestInit = {};\r\n if (options?.priority) {\r\n fetchOptions.priority = options.priority;\r\n }\r\n\r\n const response = await fetch(url, fetchOptions);\r\n if (!response.ok) {\r\n if (response.status === 404) return null; // HTTP_STATUS.NOT_FOUND\r\n throw new Error(`Failed to fetch RSC: ${response.statusText}`);\r\n }\r\n\r\n const rscPayload = await response.json();\r\n return {\r\n html: rscPayload.html,\r\n scripts: rscPayload.scripts || \"\",\r\n styles: rscPayload.styles || \"\",\r\n islandData: rscPayload.islandData || {},\r\n };\r\n } catch (error) {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Load component for client-side fallback\r\n */\r\nasync function loadComponent(route: ClientRouteLoaded): Promise<any> {\r\n try {\r\n const module = await route.component();\r\n const Component = module.default || module;\r\n\r\n if (!Component) {\r\n throw new Error(ERROR_MESSAGES.COMPONENT_NOT_FOUND(route.path));\r\n }\r\n\r\n return (props: any) => {\r\n const safeProps =\r\n props && typeof props === \"object\" && !Array.isArray(props)\r\n ? props\r\n : { params: {}, searchParams: {} };\r\n\r\n if (typeof Component === \"function\") {\r\n return Component(safeProps);\r\n }\r\n return Component;\r\n };\r\n } catch (error) {\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Boot islands helper\r\n */\r\nfunction bootIslandsNow() {\r\n bootIslands();\r\n}\r\n\r\n// Global router instance (set by bootstrapClient)\r\nlet globalRouter: FrameworkRouter | null = null;\r\n\r\n/**\r\n * Set global router instance\r\n */\r\nexport function setGlobalRouter(router: FrameworkRouter) {\r\n globalRouter = router;\r\n}\r\n\r\n/**\r\n * Get global router instance\r\n */\r\nexport function getGlobalRouter(): FrameworkRouter | null {\r\n return globalRouter;\r\n}\r\n\r\n/**\r\n * Navigate function that uses framework router if available\r\n * This can be used by Link components or programmatically\r\n */\r\nexport function navigate(to: string, options: { replace?: boolean } = {}) {\r\n const router = getGlobalRouter();\r\n if (router) {\r\n router.navigate(to, options);\r\n } else {\r\n // Fallback to browser navigation if router not initialized\r\n if (options.replace) {\r\n window.history.replaceState({}, \"\", to);\r\n } else {\r\n window.history.pushState({}, \"\", to);\r\n }\r\n window.location.href = to;\r\n }\r\n}\r\n\r\n/**\r\n * Framework-specific router for SPA navigation with RSC\r\n */\r\nexport class FrameworkRouter {\r\n private routes: ClientRouteLoaded[];\r\n private currentLocation: LocationState;\r\n private appContainer: HTMLElement;\r\n private componentCache = new Map<string, any>();\r\n private loadedScripts = new Set<string>(); // Track loaded scripts\r\n private routeStyles = new Map<string, HTMLLinkElement[]>(); // Track route-specific styles\r\n private rscPayloadCache: LRUCache<string, RSCPayload>;\r\n private prefetchPromises = new Map<string, Promise<RSCPayload | null>>();\r\n private prefetchObserver: IntersectionObserver | null = null;\r\n private readonly MAX_CACHE_SIZE = 10;\r\n private invalidatedPaths = new Set<string>(); // Prepared for revalidatePath\r\n private prefetchedLinks = new Set<string>(); // Track links that have been pre-fetched\r\n\r\n constructor(routes: ClientRouteLoaded[], appContainer: HTMLElement) {\r\n this.routes = routes;\r\n this.appContainer = appContainer;\r\n this.currentLocation = getInitialLocation();\r\n this.rscPayloadCache = new LRUCache<string, RSCPayload>(this.MAX_CACHE_SIZE);\r\n\r\n // Set as global router\r\n setGlobalRouter(this);\r\n\r\n this.setupNavigation();\r\n this.setupPopState();\r\n this.setupPrefetch();\r\n }\r\n\r\n /**\r\n * Check if pre-fetch should be performed based on connection\r\n */\r\n private shouldPrefetch(): boolean {\r\n // Check if navigator.connection is available\r\n const connection = (navigator as any).connection || (navigator as any).mozConnection || (navigator as any).webkitConnection;\r\n \r\n if (!connection) {\r\n // If connection API is not available, allow pre-fetch\r\n return true;\r\n }\r\n\r\n // Don't pre-fetch on slow connections\r\n if (connection.effectiveType === 'slow-2g' || connection.effectiveType === '2g') {\r\n return false;\r\n }\r\n\r\n // Don't pre-fetch if data saver is enabled\r\n if (connection.saveData === true) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Generate cache key from pathname and search\r\n */\r\n private getCacheKey(pathname: string, search: string = \"\"): string {\r\n return `${normalizeUrlPath(pathname)}${search || ''}`;\r\n }\r\n\r\n /**\r\n * Check if href is an internal link\r\n */\r\n private isInternalLink(href: string | null): boolean {\r\n if (!href) return false;\r\n\r\n // Skip external links, mailto, tel, etc.\r\n if (\r\n href.startsWith(\"http\") ||\r\n href.startsWith(\"//\") ||\r\n href.startsWith(\"mailto:\") ||\r\n href.startsWith(\"tel:\")\r\n ) {\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n /**\r\n * Pre-fetch route data (RSC payload and JS component)\r\n */\r\n private async prefetchRoute(pathname: string, search: string = \"\"): Promise<RSCPayload | null> {\r\n // Check if pre-fetch should be performed\r\n if (!this.shouldPrefetch()) {\r\n return null;\r\n }\r\n\r\n const key = this.getCacheKey(pathname, search);\r\n\r\n // Check if path is invalidated\r\n if (this.invalidatedPaths.has(key)) {\r\n return null;\r\n }\r\n\r\n // If already in cache, mark as pre-fetched and return immediately\r\n const cached = this.rscPayloadCache.get(key);\r\n if (cached) {\r\n this.prefetchedLinks.add(key);\r\n return cached;\r\n }\r\n\r\n // If pre-fetch is already in progress, return that promise\r\n if (this.prefetchPromises.has(key)) {\r\n return this.prefetchPromises.get(key)!;\r\n }\r\n\r\n // Start pre-fetch with low priority\r\n const promise = fetchRSCPayload(pathname, search, { priority: 'low' })\r\n .then((payload) => {\r\n if (payload) {\r\n // Cache the payload (LRU handles size limit automatically)\r\n this.rscPayloadCache.set(key, payload);\r\n // Mark as pre-fetched\r\n this.prefetchedLinks.add(key);\r\n\r\n // Pre-load JS component in background if route exists\r\n const route = this.findRoute(pathname);\r\n if (route) {\r\n this.loadComponentCached(route).catch(() => {\r\n // Silently fail - this is just pre-loading\r\n });\r\n }\r\n }\r\n return payload;\r\n })\r\n .catch((error) => {\r\n // Silently fail - pre-fetch should not affect UX\r\n if (typeof console !== 'undefined' && console.debug) {\r\n console.debug('[loly-core] Pre-fetch failed:', error);\r\n }\r\n return null;\r\n })\r\n .finally(() => {\r\n // Clean up promise from map\r\n this.prefetchPromises.delete(key);\r\n });\r\n\r\n this.prefetchPromises.set(key, promise);\r\n return promise;\r\n }\r\n\r\n /**\r\n * Navigate to a new path\r\n */\r\n navigate(to: string, options: { replace?: boolean } = {}) {\r\n const next = normalizePath(to);\r\n\r\n if (options.replace) {\r\n window.history.replaceState({}, \"\", to);\r\n } else {\r\n window.history.pushState({}, \"\", to);\r\n }\r\n\r\n this.currentLocation = next;\r\n this.updateContent();\r\n\r\n // Scroll to top or hash\r\n if (!next.hash) {\r\n window.scrollTo({ top: 0 });\r\n } else {\r\n const el = document.getElementById(next.hash.slice(1));\r\n if (el) {\r\n el.scrollIntoView();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Update app content based on current location\r\n */\r\n private async updateContent() {\r\n const { pathname, search } = this.currentLocation;\r\n const key = this.getCacheKey(pathname, search);\r\n\r\n // Check cache first\r\n let rscPayload: RSCPayload | null = this.rscPayloadCache.get(key) || null;\r\n\r\n // If not in cache, fetch normally\r\n if (!rscPayload) {\r\n rscPayload = await fetchRSCPayload(pathname, search);\r\n \r\n // Cache the result if successful\r\n if (rscPayload) {\r\n this.rscPayloadCache.set(key, rscPayload);\r\n }\r\n }\r\n\r\n // Clean up prefetch promise if it exists\r\n this.prefetchPromises.delete(key);\r\n\r\n if (rscPayload) {\r\n // 1. Check if HTML contains islands BEFORE loading component\r\n const hasIslands = rscPayload.html.includes(\"data-loly-island\");\r\n\r\n // 2. Load route component ONLY if there are islands (to register them)\r\n if (hasIslands) {\r\n const route = this.findRoute(pathname);\r\n if (route) {\r\n try {\r\n // Load component to register islands (even though we won't render it)\r\n await this.loadComponentCached(route);\r\n } catch (err) {\r\n console.warn(\r\n \"[loly-core] Failed to load route component for island registration:\",\r\n err\r\n );\r\n }\r\n }\r\n }\r\n\r\n // 3. Inject island data BEFORE updating DOM\r\n if (\r\n rscPayload.islandData &&\r\n Object.keys(rscPayload.islandData).length > 0\r\n ) {\r\n if (!(window as any).__LOLY_ISLAND_DATA__) {\r\n (window as any).__LOLY_ISLAND_DATA__ = {};\r\n }\r\n Object.assign(\r\n (window as any).__LOLY_ISLAND_DATA__,\r\n rscPayload.islandData\r\n );\r\n }\r\n\r\n // 4. Use DocumentFragment for better performance\r\n const fragment = document.createDocumentFragment();\r\n const tempDiv = document.createElement(\"div\");\r\n tempDiv.innerHTML = rscPayload.html;\r\n\r\n // Move all nodes to fragment\r\n while (tempDiv.firstChild) {\r\n fragment.appendChild(tempDiv.firstChild);\r\n }\r\n\r\n // 5. Clear container and append fragment (single DOM operation)\r\n this.appContainer.innerHTML = \"\";\r\n this.appContainer.appendChild(fragment);\r\n\r\n // 6. Inject styles (with deduplication)\r\n if (rscPayload.styles) {\r\n this.injectStyles(pathname, rscPayload.styles);\r\n }\r\n\r\n // 7. Inject scripts (with deduplication)\r\n if (rscPayload.scripts) {\r\n await this.injectScripts(rscPayload.scripts);\r\n }\r\n\r\n // 8. Boot islands after DOM is ready and component is loaded (if needed)\r\n requestAnimationFrame(() => {\r\n requestAnimationFrame(() => {\r\n bootIslandsNow();\r\n // Observe new links in the updated content\r\n this.observeNewLinks(this.appContainer);\r\n });\r\n });\r\n return;\r\n }\r\n\r\n // Fallback: load component and render in client\r\n const route = this.findRoute(pathname);\r\n if (route) {\r\n try {\r\n const Component = await this.loadComponentCached(route);\r\n const searchParams = Object.fromEntries(\r\n new URLSearchParams(search || \"\")\r\n );\r\n const params = extractRouteParams(route.path, pathname);\r\n\r\n // Render component\r\n const result = Component({ params, searchParams });\r\n\r\n // Clear and mount\r\n this.appContainer.innerHTML = \"\";\r\n mount(result, this.appContainer);\r\n\r\n // Boot islands\r\n requestAnimationFrame(() => {\r\n requestAnimationFrame(() => {\r\n bootIslandsNow();\r\n // Activate async components\r\n activateAsyncComponents(this.appContainer);\r\n // Observe new links in the updated content\r\n this.observeNewLinks(this.appContainer);\r\n });\r\n });\r\n } catch (err) {\r\n this.appContainer.innerHTML = \"<div>Error loading route</div>\";\r\n }\r\n } else {\r\n this.appContainer.innerHTML = \"<div>404 - Not Found</div>\";\r\n }\r\n }\r\n\r\n /**\r\n * Inject styles for a route with deduplication\r\n */\r\n private injectStyles(routePath: string, styles: string): void {\r\n // Remove previous route-specific styles (but keep globals.css)\r\n const existing = this.routeStyles.get(routePath);\r\n if (existing) {\r\n existing.forEach((link) => {\r\n // Only remove if it's not globals.css (which should persist)\r\n if (!link.href.includes(\"globals.css\")) {\r\n link.remove();\r\n }\r\n });\r\n }\r\n\r\n if (!styles.trim()) return;\r\n\r\n // Parse link tags from HTML string\r\n const tempDiv = document.createElement(\"div\");\r\n tempDiv.innerHTML = styles.trim();\r\n\r\n const linkElements: HTMLLinkElement[] = [];\r\n const links = tempDiv.querySelectorAll('link[rel=\"stylesheet\"]');\r\n\r\n links.forEach((link) => {\r\n const href = link.getAttribute(\"href\") || \"\";\r\n\r\n // Skip globals.css - it should only be loaded once in initial HTML\r\n if (href.includes(\"globals.css\")) {\r\n return;\r\n }\r\n\r\n const linkEl = document.createElement(\"link\");\r\n linkEl.rel = \"stylesheet\";\r\n linkEl.href = href;\r\n linkEl.setAttribute(\"data-route-styles\", routePath);\r\n\r\n // Check for duplicates by href\r\n const existingLink = document.querySelector(\r\n `link[rel=\"stylesheet\"][href=\"${href}\"]`\r\n );\r\n if (!existingLink) {\r\n document.head.appendChild(linkEl);\r\n linkElements.push(linkEl);\r\n }\r\n });\r\n\r\n if (linkElements.length > 0) {\r\n this.routeStyles.set(routePath, linkElements);\r\n }\r\n }\r\n\r\n /**\r\n * Inject scripts with deduplication\r\n */\r\n private async injectScripts(scripts: string): Promise<void> {\r\n if (!scripts.trim()) return;\r\n\r\n // Parse script tags efficiently\r\n const tempDiv = document.createElement(\"div\");\r\n tempDiv.innerHTML = scripts;\r\n const scriptTags = tempDiv.querySelectorAll(\"script\");\r\n\r\n const loadPromises: Promise<void>[] = [];\r\n\r\n scriptTags.forEach((script) => {\r\n const src = script.getAttribute(\"src\");\r\n\r\n if (src) {\r\n // External script - check if already loaded\r\n if (this.loadedScripts.has(src)) {\r\n return; // Skip if already loaded\r\n }\r\n\r\n this.loadedScripts.add(src);\r\n\r\n // Load external script\r\n const promise = new Promise<void>((resolve, reject) => {\r\n const newScript = document.createElement(\"script\");\r\n newScript.type = \"module\";\r\n newScript.src = src;\r\n newScript.onload = () => resolve();\r\n newScript.onerror = () => {\r\n this.loadedScripts.delete(src); // Remove on error to allow retry\r\n reject(new Error(`Failed to load script: ${src}`));\r\n };\r\n document.head.appendChild(newScript);\r\n });\r\n\r\n loadPromises.push(promise);\r\n } else {\r\n // Inline script - execute directly\r\n const inlineScript = document.createElement(\"script\");\r\n inlineScript.type = \"module\";\r\n inlineScript.textContent = script.textContent || \"\";\r\n document.head.appendChild(inlineScript);\r\n // Remove after execution to avoid memory leaks\r\n setTimeout(() => inlineScript.remove(), 0);\r\n }\r\n });\r\n\r\n // Wait for all external scripts to load\r\n await Promise.all(loadPromises);\r\n }\r\n\r\n /**\r\n * Find matching route for pathname\r\n */\r\n private findRoute(pathname: string): ClientRouteLoaded | null {\r\n // Simple exact match first\r\n const exact = this.routes.find((r) => r.path === pathname);\r\n if (exact) return exact;\r\n\r\n // Try dynamic routes\r\n for (const route of this.routes) {\r\n if (matchesRoute(route.path, pathname)) {\r\n return route;\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * Load component with caching\r\n */\r\n private async loadComponentCached(route: ClientRouteLoaded): Promise<any> {\r\n if (this.componentCache.has(route.path)) {\r\n return this.componentCache.get(route.path);\r\n }\r\n\r\n const Component = await loadComponent(route);\r\n this.componentCache.set(route.path, Component);\r\n return Component;\r\n }\r\n\r\n /**\r\n * Setup navigation interception\r\n */\r\n private setupNavigation() {\r\n // Intercept all link clicks\r\n document.addEventListener(\"click\", (e) => {\r\n const target = e.target as HTMLElement;\r\n const link = target.closest(\"a\");\r\n\r\n if (!link) return;\r\n\r\n const href = link.getAttribute(\"href\");\r\n if (!href) return;\r\n\r\n // Skip external links, mailto, tel, etc.\r\n if (\r\n href.startsWith(\"http\") ||\r\n href.startsWith(\"//\") ||\r\n href.startsWith(\"mailto:\") ||\r\n href.startsWith(\"tel:\")\r\n ) {\r\n return;\r\n }\r\n\r\n // Skip if modifier keys are pressed\r\n if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey || e.button !== 0) {\r\n return;\r\n }\r\n\r\n // Skip if target is not self\r\n if (link.target && link.target !== \"_self\") {\r\n return;\r\n }\r\n\r\n // Skip if already prevented\r\n if (e.defaultPrevented) {\r\n return;\r\n }\r\n\r\n // Prevent default and navigate\r\n e.preventDefault();\r\n this.navigate(href);\r\n });\r\n }\r\n\r\n /**\r\n * Setup popstate handler for browser back/forward\r\n */\r\n private setupPopState() {\r\n window.addEventListener(\"popstate\", () => {\r\n this.currentLocation = getInitialLocation();\r\n this.updateContent();\r\n });\r\n }\r\n\r\n /**\r\n * Observe new links in container (called after DOM updates)\r\n */\r\n private observeNewLinks(container: HTMLElement): void {\r\n if (!this.prefetchObserver) return;\r\n\r\n const links = container.querySelectorAll(\"a[href]\");\r\n links.forEach((link) => {\r\n const href = link.getAttribute(\"href\");\r\n if (href && this.isInternalLink(href)) {\r\n const { pathname, search } = normalizePath(href);\r\n const key = this.getCacheKey(pathname, search);\r\n \r\n // Only observe if not in cache and not already pre-fetched\r\n if (!this.rscPayloadCache.has(key) && !this.prefetchedLinks.has(key)) {\r\n this.prefetchObserver!.observe(link);\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Setup pre-fetch with Intersection Observer and hover\r\n */\r\n private setupPrefetch(): void {\r\n // Create Intersection Observer with 200px margin (pre-fetch before visible)\r\n this.prefetchObserver = new IntersectionObserver(\r\n (entries) => {\r\n entries.forEach((entry) => {\r\n if (entry.isIntersecting) {\r\n const link = entry.target as HTMLAnchorElement;\r\n const href = link.getAttribute(\"href\");\r\n if (href && this.isInternalLink(href)) {\r\n const { pathname, search } = normalizePath(href);\r\n const key = this.getCacheKey(pathname, search);\r\n \r\n // Check if already in cache or in process\r\n if (this.rscPayloadCache.has(key) || this.prefetchPromises.has(key)) {\r\n // Already pre-fetched, disconnect from observer\r\n this.prefetchObserver!.unobserve(link);\r\n this.prefetchedLinks.add(key);\r\n return;\r\n }\r\n \r\n // Check if already pre-fetched\r\n if (this.prefetchedLinks.has(key)) {\r\n this.prefetchObserver!.unobserve(link);\r\n return;\r\n }\r\n \r\n // Mark as pre-fetched and trigger pre-fetch\r\n this.prefetchedLinks.add(key);\r\n this.prefetchRoute(pathname, search).then(() => {\r\n // Disconnect after successful pre-fetch\r\n this.prefetchObserver!.unobserve(link);\r\n });\r\n }\r\n }\r\n });\r\n },\r\n { rootMargin: \"200px\" }\r\n );\r\n\r\n // Observe all existing internal links\r\n const allLinks = document.querySelectorAll(\"a[href]\");\r\n allLinks.forEach((link) => {\r\n const href = link.getAttribute(\"href\");\r\n if (href && this.isInternalLink(href)) {\r\n const { pathname, search } = normalizePath(href);\r\n const key = this.getCacheKey(pathname, search);\r\n \r\n // Only observe if not in cache and not already pre-fetched\r\n if (!this.rscPayloadCache.has(key) && !this.prefetchedLinks.has(key)) {\r\n this.prefetchObserver!.observe(link);\r\n }\r\n }\r\n });\r\n\r\n // Hover listener with debounce (complement for desktop)\r\n let hoverTimeout: ReturnType<typeof setTimeout> | null = null;\r\n document.addEventListener(\r\n \"mouseenter\",\r\n (e) => {\r\n // Verify target is an Element before calling closest\r\n const target = e.target;\r\n if (!target || !(target instanceof Element)) {\r\n return;\r\n }\r\n \r\n const link = target.closest(\"a\");\r\n if (link) {\r\n const href = link.getAttribute(\"href\");\r\n if (href && this.isInternalLink(href)) {\r\n const { pathname, search } = normalizePath(href);\r\n const key = this.getCacheKey(pathname, search);\r\n \r\n // Skip if already in cache or already pre-fetched\r\n if (this.rscPayloadCache.has(key) || this.prefetchedLinks.has(key)) {\r\n return;\r\n }\r\n \r\n // Debounce hover to avoid excessive pre-fetches\r\n if (hoverTimeout) {\r\n clearTimeout(hoverTimeout);\r\n }\r\n hoverTimeout = setTimeout(() => {\r\n // Double-check before pre-fetching (might have been pre-fetched by observer)\r\n if (!this.rscPayloadCache.has(key) && !this.prefetchedLinks.has(key)) {\r\n this.prefetchedLinks.add(key);\r\n this.prefetchRoute(pathname, search);\r\n }\r\n }, 100);\r\n }\r\n }\r\n },\r\n true // Capture phase\r\n );\r\n }\r\n\r\n /**\r\n * Initialize router (call after initial page load)\r\n */\r\n init() {\r\n // With streaming SSR, we need to wait for DOMContentLoaded and add\r\n // a small delay to ensure HTML is fully parsed\r\n const self = this;\r\n \r\n const initIslands = () => {\r\n // Small delay to ensure streaming HTML is fully parsed\r\n setTimeout(() => {\r\n requestAnimationFrame(() => {\r\n requestAnimationFrame(() => {\r\n bootIslandsNow();\r\n // Activate async components\r\n activateAsyncComponents(self.appContainer);\r\n // Observe links in initial DOM\r\n self.observeNewLinks(self.appContainer);\r\n });\r\n });\r\n }, 0);\r\n };\r\n\r\n if (document.readyState === \"loading\") {\r\n document.addEventListener(\"DOMContentLoaded\", initIslands, { once: true });\r\n } else {\r\n // DOM already loaded\r\n initIslands();\r\n }\r\n }\r\n\r\n /**\r\n * Invalidate cache for a specific path (prepared for future revalidatePath implementation)\r\n * TODO: Implementar invalidación completa cuando se implemente revalidatePath\r\n */\r\n public revalidatePath(pathname: string, search: string = \"\"): void {\r\n const key = this.getCacheKey(pathname, search);\r\n \r\n // Add to invalidated paths\r\n this.invalidatedPaths.add(key);\r\n \r\n // Remove from cache\r\n this.rscPayloadCache.delete(key);\r\n \r\n // Remove from prefetch promises if exists\r\n this.prefetchPromises.delete(key);\r\n \r\n // Remove from prefetched links so it can be pre-fetched again\r\n this.prefetchedLinks.delete(key);\r\n }\r\n}\r\n","import { normalizeUrlPath } from \"./path\";\r\n\r\n/**\r\n * Result of a route pattern match\r\n */\r\nexport interface MatchResult {\r\n params: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Match a route pattern against a pathname\r\n * Supports dynamic segments (:param) and catch-all (*param)\r\n */\r\nexport function matchRoutePattern(\r\n pattern: string,\r\n pathname: string\r\n): MatchResult | null {\r\n const normalizedPattern = normalizeUrlPath(pattern);\r\n const normalizedPathname = normalizeUrlPath(pathname);\r\n\r\n // Exact match\r\n if (normalizedPattern === normalizedPathname) {\r\n return { params: {} };\r\n }\r\n\r\n const patternParts = normalizedPattern.split(\"/\").filter(Boolean);\r\n const pathParts = normalizedPathname.split(\"/\").filter(Boolean);\r\n\r\n // Handle root route\r\n if (patternParts.length === 0 && pathParts.length === 0) {\r\n return { params: {} };\r\n }\r\n\r\n const params: Record<string, string> = {};\r\n let patternIdx = 0;\r\n let pathIdx = 0;\r\n\r\n while (patternIdx < patternParts.length && pathIdx < pathParts.length) {\r\n const patternPart = patternParts[patternIdx];\r\n const pathPart = pathParts[pathIdx];\r\n\r\n // Catch-all route (*param)\r\n if (patternPart.startsWith(\"*\")) {\r\n const paramName = patternPart.slice(1);\r\n const remaining = pathParts.slice(pathIdx);\r\n if (paramName) {\r\n params[paramName] = remaining.join(\"/\");\r\n }\r\n return { params };\r\n }\r\n\r\n // Dynamic segment (:param)\r\n if (patternPart.startsWith(\":\")) {\r\n const paramName = patternPart.slice(1);\r\n params[paramName] = decodeURIComponent(pathPart);\r\n patternIdx++;\r\n pathIdx++;\r\n continue;\r\n }\r\n\r\n // Exact match required\r\n if (patternPart === pathPart) {\r\n patternIdx++;\r\n pathIdx++;\r\n continue;\r\n }\r\n\r\n // No match\r\n return null;\r\n }\r\n\r\n // All parts must be consumed\r\n if (patternIdx === patternParts.length && pathIdx === pathParts.length) {\r\n return { params };\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/**\r\n * Extract route parameters from a pathname based on a pattern\r\n */\r\nexport function extractRouteParams(\r\n pattern: string,\r\n pathname: string\r\n): Record<string, string> {\r\n const match = matchRoutePattern(pattern, pathname);\r\n return match?.params || {};\r\n}\r\n\r\n/**\r\n * Normalize a route path (for consistency)\r\n */\r\nexport function normalizeRoutePath(path: string): string {\r\n return normalizeUrlPath(path);\r\n}\r\n\r\n/**\r\n * Check if a pathname matches a route pattern\r\n */\r\nexport function matchesRoute(pattern: string, pathname: string): boolean {\r\n // Handle exact matches\r\n if (pattern === pathname) return true;\r\n\r\n const normalizedPattern = normalizeUrlPath(pattern);\r\n const normalizedPathname = normalizeUrlPath(pathname);\r\n\r\n if (normalizedPattern === normalizedPathname) return true;\r\n\r\n // Handle dynamic routes like /article/:id\r\n // Escape special regex characters except : and *\r\n const escaped = normalizedPattern.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\r\n const regex = new RegExp(\r\n \"^\" + escaped.replace(/:[^/]+/g, \"([^/]+)\") + \"/?$\"\r\n );\r\n return regex.test(normalizedPathname);\r\n}\r\n\r\n","import { FrameworkRouter } from \"./router\";\r\nimport type { BootstrapOptions } from \"./types\";\r\nimport { SERVER, ERROR_MESSAGES } from \"../constants\";\r\nimport { matchesRoute } from \"../utils/route-matcher\";\r\n\r\n/**\r\n * Load a component (for pre-loading current route to register islands)\r\n */\r\nasync function loadComponent(route: { path: string; component: () => Promise<any> }): Promise<any> {\r\n try {\r\n const module = await route.component();\r\n const Component = module.default || module;\r\n \r\n if (!Component) {\r\n throw new Error(ERROR_MESSAGES.COMPONENT_NOT_FOUND(route.path));\r\n }\r\n\r\n return Component;\r\n } catch (error) {\r\n console.error(ERROR_MESSAGES.FAILED_TO_LOAD_ROUTE_COMPONENT(route.path), error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Bootstrap client application\r\n */\r\nexport function bootstrapClient(options: BootstrapOptions): void {\r\n const { routes } = options;\r\n\r\n const appContainer = document.getElementById(SERVER.APP_CONTAINER_ID);\r\n if (!appContainer) {\r\n console.error(ERROR_MESSAGES.APP_CONTAINER_NOT_FOUND);\r\n return;\r\n }\r\n\r\n // Pre-load current route component to register islands\r\n const currentPath = window.location.pathname;\r\n const currentRoute = routes.find((route) => matchesRoute(route.path, currentPath));\r\n\r\n // Pre-load current route to register islands\r\n if (currentRoute) {\r\n loadComponent(currentRoute)\r\n .then(() => {\r\n // Islands registered, will be booted by router.init()\r\n })\r\n .catch(() => {\r\n // Continue anyway\r\n });\r\n }\r\n\r\n // Create and initialize framework router\r\n const router = new FrameworkRouter(routes, appContainer);\r\n router.init();\r\n}\r\n\r\n","import rspackBuild from \"@rspack/core\";\r\nimport { join } from \"path\";\r\nimport { existsSync, mkdirSync } from \"fs\";\r\nimport { scanRoutes } from \"../router/scanner\";\r\nimport type { RouteConfig } from \"../router/types\";\r\nimport { generateRoutesManifest, generateBootstrap } from \"./manifest\";\r\nimport { createClientConfig } from \"./client\";\r\nimport { buildServerFiles } from \"./server\";\r\nimport { processCssWithPostCSS } from \"./css-processor\";\r\nimport {\r\n setContext,\r\n getAppDirPath,\r\n getAppDir,\r\n getSrcDir,\r\n getOutDir,\r\n getClientDir,\r\n getProjectDir,\r\n setRouteConfig,\r\n} from \"../context\";\r\nimport { DIRECTORIES, FILE_NAMES, ERROR_MESSAGES } from \"../constants\";\r\n\r\nexport interface BuildOptions {\r\n projectDir: string;\r\n outDir?: string;\r\n mode?: \"development\" | \"production\";\r\n}\r\n\r\n/**\r\n * Execute the build\r\n */\r\nexport async function buildProject(options: BuildOptions): Promise<void> {\r\n const {\r\n projectDir,\r\n outDir = join(projectDir, DIRECTORIES.LOLY, DIRECTORIES.DIST),\r\n } = options;\r\n const appDir = getAppDirPath(projectDir);\r\n const srcDir = join(projectDir, DIRECTORIES.SRC);\r\n\r\n if (!existsSync(appDir)) {\r\n throw new Error(ERROR_MESSAGES.APP_DIR_NOT_FOUND(projectDir));\r\n }\r\n\r\n // Initialize context\r\n setContext({\r\n projectDir,\r\n appDir,\r\n srcDir,\r\n outDir,\r\n buildMode: options.mode || \"production\",\r\n isDev: options.mode === \"development\",\r\n });\r\n\r\n // 1. Scan routes\r\n const routeConfig = await scanRoutes(getAppDir());\r\n setRouteConfig(routeConfig);\r\n\r\n // 2. Generate bootstrap.ts for client (needed before client build)\r\n const pageRoutes = routeConfig.routes.filter((r) => r.type === \"page\");\r\n generateBootstrap(getProjectDir(), pageRoutes);\r\n\r\n // 3. Build client (needed before generating manifest with chunk info)\r\n const clientConfig = await createClientConfig(options);\r\n try {\r\n await new Promise<void>((resolve, reject) => {\r\n const compiler = rspackBuild(clientConfig);\r\n compiler.run((err, stats) => {\r\n if (err) {\r\n console.error(\"[loly-core] Client build error:\", err);\r\n reject(err);\r\n return;\r\n }\r\n if (stats && stats.hasErrors()) {\r\n console.error(\"[loly-core] Client build has errors\");\r\n console.error(stats.compilation.errors);\r\n reject(new Error(ERROR_MESSAGES.CLIENT_BUILD_FAILED));\r\n return;\r\n }\r\n resolve();\r\n });\r\n });\r\n } catch (error) {\r\n console.error(ERROR_MESSAGES.CLIENT_BUILD_FAILED, error);\r\n throw error;\r\n }\r\n\r\n // 3.5. Process globals.css to client output if it exists\r\n // Try src/globals.css first, then src/app/globals.css\r\n const globalsCssPath = existsSync(join(getSrcDir(), FILE_NAMES.GLOBALS_CSS))\r\n ? join(getSrcDir(), FILE_NAMES.GLOBALS_CSS)\r\n : existsSync(join(getAppDir(), FILE_NAMES.GLOBALS_CSS))\r\n ? join(getAppDir(), FILE_NAMES.GLOBALS_CSS)\r\n : null;\r\n\r\n const clientOutDir = getClientDir();\r\n if (globalsCssPath && existsSync(globalsCssPath)) {\r\n const destCssPath = join(clientOutDir, FILE_NAMES.GLOBALS_CSS);\r\n await processCssWithPostCSS({\r\n inputPath: globalsCssPath,\r\n outputPath: destCssPath,\r\n projectDir: getProjectDir(),\r\n });\r\n }\r\n\r\n // 4. Build server (src/app/ directory) using esbuild\r\n try {\r\n await buildServerFiles(options);\r\n } catch (error) {\r\n console.error(ERROR_MESSAGES.SERVER_BUILD_FAILED, error);\r\n throw error;\r\n }\r\n\r\n // 5. Generate routes manifest (after both builds, so we can include chunk info)\r\n generateRoutesManifest(routeConfig, getProjectDir(), getAppDir());\r\n}\r\n\r\n","import { writeFileSync, mkdirSync, existsSync, readFileSync } from \"fs\";\r\nimport { join, dirname, relative, resolve } from \"path\";\r\nimport type { RouteConfig } from \"../router/types\";\r\nimport {\r\n getProjectDir,\r\n getServerOutDir,\r\n getManifestPath,\r\n getRoutesManifestPath,\r\n getBootstrapPath,\r\n} from \"../context\";\r\nimport { DIRECTORIES, FILE_NAMES } from \"../constants\";\r\n\r\n/**\r\n * Map source TSX file path to compiled server file path\r\n */\r\nfunction getServerCompiledPath(\r\n sourcePath: string,\r\n appDir: string\r\n): string {\r\n // Get relative path from appDir to source file\r\n const relativePath = relative(appDir, sourcePath);\r\n // Remove extension (.tsx, .ts, .jsx, .js) and replace with .js\r\n const relativeWithoutExt = relativePath.replace(/\\.(tsx?|jsx?)$/, \".js\");\r\n // Build compiled path in .loly/dist/server/\r\n const serverDistDir = getServerOutDir();\r\n return join(serverDistDir, relativeWithoutExt).replace(/\\\\/g, \"/\");\r\n}\r\n\r\n/**\r\n * Read client manifest and map route chunks\r\n */\r\nfunction getClientChunksForRoute(\r\n routeIndex: number,\r\n clientManifestPath: string\r\n): { js: string[]; css: string[] } | null {\r\n if (!existsSync(clientManifestPath)) {\r\n return null;\r\n }\r\n\r\n try {\r\n const manifestContent = readFileSync(clientManifestPath, \"utf-8\");\r\n const manifest: ChunkManifest = JSON.parse(manifestContent);\r\n\r\n const chunkName = `route-${routeIndex}`;\r\n const chunk = manifest[chunkName];\r\n\r\n if (!chunk) {\r\n return null;\r\n }\r\n\r\n const js: string[] = [];\r\n const css: string[] = [];\r\n\r\n // Add main chunk file\r\n if (chunk.file) {\r\n js.push(chunk.file);\r\n }\r\n\r\n // Add CSS files\r\n if (chunk.css && chunk.css.length > 0) {\r\n css.push(...chunk.css);\r\n }\r\n\r\n // Add imported chunks\r\n if (chunk.imports && chunk.imports.length > 0) {\r\n for (const importName of chunk.imports) {\r\n const importChunk = manifest[importName];\r\n if (importChunk?.file) {\r\n js.push(importChunk.file);\r\n }\r\n if (importChunk?.css && importChunk.css.length > 0) {\r\n css.push(...importChunk.css);\r\n }\r\n }\r\n }\r\n\r\n return { js, css };\r\n } catch (error) {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Generate routes manifest for client\r\n */\r\nexport function generateRoutesManifest(\r\n config: RouteConfig,\r\n projectDir: string,\r\n appDir: string\r\n): void {\r\n const manifestDir = join(getProjectDir(), DIRECTORIES.LOLY);\r\n if (!existsSync(manifestDir)) {\r\n mkdirSync(manifestDir, { recursive: true });\r\n }\r\n\r\n // Try to read client manifest to get chunk information\r\n const clientManifestPath = getManifestPath();\r\n const hasClientManifest = existsSync(clientManifestPath);\r\n\r\n // Convert RouteFile to serializable format\r\n // Map pages to their route index for chunk lookup\r\n const pageRoutes = config.routes.filter((r) => r.type === \"page\");\r\n let routeIndex = 0;\r\n\r\n const routesData = config.routes.map((route) => {\r\n const sourcePath = route.filePath;\r\n const serverPath = getServerCompiledPath(sourcePath, appDir);\r\n\r\n // Get client chunks for page routes\r\n let clientChunks: { js: string[]; css: string[] } | null = null;\r\n if (route.type === \"page\" && hasClientManifest) {\r\n clientChunks = getClientChunksForRoute(routeIndex, clientManifestPath);\r\n routeIndex++;\r\n }\r\n\r\n return {\r\n sourcePath, // Original TSX path (for development)\r\n serverPath, // Compiled server path (for production)\r\n segments: route.segments,\r\n type: route.type,\r\n isRootLayout: route.isRootLayout,\r\n urlPath: route.urlPath,\r\n isApiRoute: route.isApiRoute || undefined,\r\n httpMethods: route.httpMethods || undefined,\r\n clientChunks: clientChunks || undefined, // Client chunks for this route\r\n };\r\n });\r\n\r\n const rootLayoutData = config.rootLayout\r\n ? {\r\n sourcePath: config.rootLayout.filePath,\r\n serverPath: getServerCompiledPath(\r\n config.rootLayout.filePath,\r\n appDir\r\n ),\r\n segments: config.rootLayout.segments,\r\n type: config.rootLayout.type,\r\n isRootLayout: config.rootLayout.isRootLayout,\r\n urlPath: config.rootLayout.urlPath,\r\n }\r\n : undefined;\r\n\r\n routeIndex = 0;\r\n const routeMapData = Array.from(config.routeMap.entries()).map(\r\n ([path, route]) => {\r\n const sourcePath = route.filePath;\r\n const serverPath = getServerCompiledPath(sourcePath, appDir);\r\n\r\n // Get client chunks for page routes\r\n let clientChunks: { js: string[]; css: string[] } | null = null;\r\n if (hasClientManifest) {\r\n clientChunks = getClientChunksForRoute(routeIndex, clientManifestPath);\r\n routeIndex++;\r\n }\r\n\r\n return {\r\n path,\r\n sourcePath,\r\n serverPath,\r\n segments: route.segments,\r\n type: route.type,\r\n isRootLayout: route.isRootLayout,\r\n urlPath: route.urlPath,\r\n isApiRoute: route.isApiRoute || undefined,\r\n httpMethods: route.httpMethods || undefined,\r\n clientChunks: clientChunks || undefined,\r\n };\r\n }\r\n );\r\n\r\n // Add API routes to routeMapData\r\n if (config.apiRouteMap) {\r\n for (const [path, route] of config.apiRouteMap.entries()) {\r\n const sourcePath = route.filePath;\r\n const serverPath = getServerCompiledPath(sourcePath, appDir);\r\n\r\n routeMapData.push({\r\n path,\r\n sourcePath,\r\n serverPath,\r\n segments: route.segments,\r\n type: route.type,\r\n isRootLayout: route.isRootLayout,\r\n urlPath: route.urlPath,\r\n isApiRoute: route.isApiRoute || undefined,\r\n httpMethods: route.httpMethods || undefined,\r\n clientChunks: undefined, // API routes don't have client chunks\r\n });\r\n }\r\n }\r\n\r\n const manifest = {\r\n routes: routesData,\r\n rootLayout: rootLayoutData,\r\n routeMap: routeMapData,\r\n };\r\n\r\n const manifestPath = getRoutesManifestPath();\r\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));\r\n}\r\n\r\n/**\r\n * Generate bootstrap.ts file for client\r\n */\r\nexport function generateBootstrap(projectDir: string, routes: any[]): void {\r\n const bootstrapDir = join(getProjectDir(), DIRECTORIES.LOLY);\r\n if (!existsSync(bootstrapDir)) {\r\n mkdirSync(bootstrapDir, { recursive: true });\r\n }\r\n\r\n // Generate route imports\r\n // Bootstrap is in .loly/bootstrap.ts, routes are in src/app/\r\n // So we need ../src/app/... paths\r\n const routeImports = routes\r\n .map((route, index) => {\r\n // Get relative path from project root to route file\r\n const routePath = route.filePath.replace(/\\\\/g, \"/\");\r\n const projectPath = getProjectDir().replace(/\\\\/g, \"/\");\r\n let relativePath = routePath.replace(projectPath, \"\").replace(/^\\//, \"\");\r\n\r\n // Bootstrap is in .loly/, so we need to go up one level\r\n relativePath = `../${relativePath}`;\r\n\r\n return ` {\r\n path: \"${route.urlPath}\",\r\n component: async () => {\r\n const mod = await import(/* webpackChunkName: \"route-${index}\" */ \"${relativePath}\");\r\n return mod.default || mod;\r\n },\r\n }`;\r\n })\r\n .join(\",\\n\");\r\n\r\n // CSS is added as separate entry point in client build, not imported here\r\n const bootstrapContent = `import { bootstrapClient } from \"loly/client\";\r\n\r\nconst routes = [\r\n${routeImports}\r\n];\r\n\r\nconst notFoundRoute = null;\r\nconst errorRoute = null;\r\n\r\ntry {\r\n bootstrapClient({\r\n routes,\r\n notFoundRoute,\r\n errorRoute,\r\n });\r\n} catch (error) {\r\n console.error(\"[bootstrap] Fatal error during bootstrap:\", error);\r\n throw error;\r\n}\r\n`;\r\n\r\n const bootstrapPath = getBootstrapPath();\r\n writeFileSync(bootstrapPath, bootstrapContent);\r\n}\r\n\r\n/**\r\n * Read Rspack manifest\r\n */\r\nexport interface ChunkManifest {\r\n [key: string]: {\r\n file: string;\r\n isEntry?: boolean;\r\n imports?: string[];\r\n css?: string[];\r\n };\r\n}\r\n\r\nexport function readRspackManifest(manifestPath: string): ChunkManifest {\r\n const { readFileSync } = require(\"fs\");\r\n const content = readFileSync(manifestPath, \"utf-8\");\r\n return JSON.parse(content);\r\n}\r\n\r\n/**\r\n * Write manifest\r\n */\r\nexport function writeManifest(\r\n manifestPath: string,\r\n manifest: ChunkManifest\r\n): void {\r\n const { writeFileSync } = require(\"fs\");\r\n\r\n const dir = dirname(manifestPath);\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n\r\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));\r\n}\r\n\r\n/**\r\n * Generate asset tags from manifest\r\n */\r\nexport function generateAssetTags(\r\n manifest: ChunkManifest,\r\n entryName: string,\r\n publicPath: string\r\n): { scripts: string; styles: string; preloads: string } {\r\n const entry = manifest[entryName];\r\n if (!entry) {\r\n return { scripts: \"\", styles: \"\", preloads: \"\" };\r\n }\r\n\r\n let scripts = \"\";\r\n let styles = \"\";\r\n let preloads = \"\";\r\n\r\n // Add main script\r\n if (entry.file) {\r\n const scriptPath = entry.file.startsWith(\"/\")\r\n ? entry.file\r\n : `${publicPath}${entry.file}`;\r\n \r\n // Preload main script for faster loading (critical for activation)\r\n // Using modulepreload for ES modules (better than preload)\r\n preloads = `<link rel=\"modulepreload\" href=\"${scriptPath}\" crossorigin>`;\r\n \r\n scripts = `<script type=\"module\" src=\"${scriptPath}\"></script>`;\r\n }\r\n\r\n // Add CSS\r\n if (entry.css && entry.css.length > 0) {\r\n styles = entry.css\r\n .map((css: string) => {\r\n const cssPath = css.startsWith(\"/\") ? css : `${publicPath}${css}`;\r\n return `<link rel=\"stylesheet\" href=\"${cssPath}\">`;\r\n })\r\n .join(\"\");\r\n }\r\n\r\n // Add imported chunks\r\n if (entry.imports && entry.imports.length > 0) {\r\n for (const importName of entry.imports) {\r\n const importEntry = manifest[importName];\r\n if (importEntry?.file) {\r\n const scriptPath = importEntry.file.startsWith(\"/\")\r\n ? importEntry.file\r\n : `${publicPath}${importEntry.file}`;\r\n scripts += `\\n<script type=\"module\" src=\"${scriptPath}\"></script>`;\r\n }\r\n if (importEntry?.css && importEntry.css.length > 0) {\r\n for (const css of importEntry.css) {\r\n const cssPath = css.startsWith(\"/\") ? css : `${publicPath}${css}`;\r\n styles += `\\n<link rel=\"stylesheet\" href=\"${cssPath}\">`;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return { scripts, styles, preloads };\r\n}\r\n","import type { Configuration } from \"@rspack/core\";\r\nimport { join, normalize, relative } from \"path\";\r\nimport { existsSync } from \"fs\";\r\nimport { getProjectDir, getBootstrapPath, getClientDir, getSrcDir } from \"../context\";\r\nimport { NODE_BUILTINS } from \"../constants\";\r\nimport { scanServerOnlyFiles } from \"./server-only\";\r\n\r\nexport interface ClientBuildOptions {\r\n projectDir: string;\r\n outDir?: string;\r\n mode?: \"development\" | \"production\";\r\n}\r\n\r\n/**\r\n * Check if PostCSS config exists in the project\r\n * Note: Rspack's type: \"css\" doesn't automatically process PostCSS.\r\n * CSS imports in code will work but won't be processed with PostCSS.\r\n * Only globals.css is processed with PostCSS via processCssWithPostCSS.\r\n */\r\nfunction hasPostCSSConfig(projectDir: string): boolean {\r\n return (\r\n existsSync(join(projectDir, \"postcss.config.js\")) ||\r\n existsSync(join(projectDir, \"postcss.config.mjs\")) ||\r\n existsSync(join(projectDir, \"postcss.config.cjs\"))\r\n );\r\n}\r\n\r\n/**\r\n * Generate inline stub code for server-only modules\r\n * This code is embedded directly in the bundle, no external file needed\r\n */\r\nfunction generateServerOnlyStubCode(): string {\r\n return `\r\nconst SERVER_ONLY_ERROR = \"This module is marked with 'use server' and can only be imported in server components.\";\r\n\r\nfunction createErrorFunction(propName) {\r\n const errorFn = function (...args) {\r\n throw new Error(SERVER_ONLY_ERROR + \" Attempted to call: \" + propName);\r\n };\r\n errorFn.toString = () => \"[ServerOnlyStub:\" + propName + \"]\";\r\n errorFn[Symbol.toStringTag] = \"Function\";\r\n errorFn.then = () => Promise.reject(new Error(SERVER_ONLY_ERROR + \" Attempted to await: \" + propName));\r\n errorFn.catch = () => Promise.reject(new Error(SERVER_ONLY_ERROR + \" Attempted to catch: \" + propName));\r\n return errorFn;\r\n}\r\n\r\nfunction createServerOnlyProxy() {\r\n return new Proxy({}, {\r\n get(_target, prop) {\r\n return createErrorFunction(String(prop));\r\n },\r\n set() {\r\n throw new Error(SERVER_ONLY_ERROR);\r\n },\r\n has() {\r\n return true;\r\n },\r\n ownKeys() {\r\n return [];\r\n },\r\n getOwnPropertyDescriptor(_target, prop) {\r\n return {\r\n enumerable: true,\r\n configurable: true,\r\n get: () => createErrorFunction(String(prop)),\r\n };\r\n },\r\n });\r\n}\r\n\r\nconst serverOnlyStub = createServerOnlyProxy();\r\nexport default serverOnlyStub;\r\n`;\r\n}\r\n\r\n/**\r\n * Check if a request path matches any server-only file\r\n * Returns the matched server-only file path or null\r\n * \r\n * This function handles multiple import patterns:\r\n * - Absolute paths: /absolute/path/to/file.ts\r\n * - Relative paths from src/: lib/storage, lib/storage.ts\r\n * - Relative paths with ../: ../../../lib/storage\r\n * - Filenames only: storage\r\n */\r\nfunction matchServerOnlyFile(\r\n request: string,\r\n serverOnlyFiles: Set<string>,\r\n srcDir: string\r\n): string | null {\r\n const normalizedSrcDir = normalize(srcDir).replace(/\\\\/g, \"/\");\r\n const normalizedRequest = request.replace(/\\\\/g, \"/\");\r\n \r\n // Try exact matches first (absolute paths)\r\n for (const serverOnlyPath of serverOnlyFiles) {\r\n const normalizedPath = normalize(serverOnlyPath).replace(/\\\\/g, \"/\");\r\n \r\n // 1. Exact match (absolute path)\r\n if (normalizedRequest === normalizedPath) {\r\n return serverOnlyPath;\r\n }\r\n \r\n // 2. Match relative path from src/ (e.g., \"lib/storage\" or \"lib/storage.ts\")\r\n const relativeFromSrc = normalizedPath.replace(normalizedSrcDir + \"/\", \"\").replace(/^\\/+/, \"\");\r\n const relativeWithoutExt = relativeFromSrc.replace(/\\.(ts|tsx|js|jsx)$/, \"\");\r\n \r\n // Match exact relative path\r\n if (normalizedRequest === relativeFromSrc || normalizedRequest === relativeWithoutExt) {\r\n return serverOnlyPath;\r\n }\r\n \r\n // Match relative path ending (e.g., request ends with \"/lib/storage\")\r\n if (\r\n normalizedRequest.endsWith(\"/\" + relativeFromSrc) ||\r\n normalizedRequest.endsWith(\"/\" + relativeWithoutExt)\r\n ) {\r\n return serverOnlyPath;\r\n }\r\n \r\n // 3. Match using path.relative for relative paths with ../\r\n // This handles cases like \"../../../lib/storage\" from different depths\r\n try {\r\n const relativePath = relative(srcDir, serverOnlyPath).replace(/\\\\/g, \"/\");\r\n const relativePathWithoutExt = relativePath.replace(/\\.(ts|tsx|js|jsx)$/, \"\");\r\n \r\n // Match exact relative path\r\n if (normalizedRequest === relativePath || normalizedRequest === relativePathWithoutExt) {\r\n return serverOnlyPath;\r\n }\r\n \r\n // Match relative path ending\r\n if (\r\n normalizedRequest.endsWith(\"/\" + relativePath) ||\r\n normalizedRequest.endsWith(\"/\" + relativePathWithoutExt)\r\n ) {\r\n return serverOnlyPath;\r\n }\r\n \r\n // Match normalized relative path (handle different ../ combinations)\r\n // Compare by normalizing both paths\r\n const requestParts = normalizedRequest.split(\"/\").filter(p => p && p !== \".\");\r\n const relativeParts = relativePathWithoutExt.split(\"/\").filter(p => p && p !== \".\");\r\n \r\n // Check if request ends with the relative parts\r\n if (relativeParts.length > 0 && requestParts.length >= relativeParts.length) {\r\n const requestEnd = requestParts.slice(-relativeParts.length).join(\"/\");\r\n const relativeEnd = relativeParts.join(\"/\");\r\n if (requestEnd === relativeEnd) {\r\n return serverOnlyPath;\r\n }\r\n }\r\n } catch {\r\n // Ignore path resolution errors\r\n }\r\n \r\n // 4. Match filename only (e.g., \"storage\" or \"storage.ts\")\r\n const filename = normalizedPath.split(\"/\").pop();\r\n if (filename) {\r\n const filenameWithoutExt = filename.replace(/\\.(ts|tsx|js|jsx)$/, \"\");\r\n \r\n // Match exact filename\r\n if (normalizedRequest === filename || normalizedRequest === filenameWithoutExt) {\r\n return serverOnlyPath;\r\n }\r\n \r\n // Match filename ending\r\n if (\r\n normalizedRequest.endsWith(\"/\" + filename) ||\r\n normalizedRequest.endsWith(\"/\" + filenameWithoutExt)\r\n ) {\r\n return serverOnlyPath;\r\n }\r\n }\r\n \r\n // 5. Match by resolving the request relative to common import contexts\r\n // This handles cases where the request is a relative path that should resolve to the server-only file\r\n try {\r\n // If request doesn't start with / and doesn't start with ./, try resolving it\r\n if (!normalizedRequest.startsWith(\"/\") && !normalizedRequest.startsWith(\".\")) {\r\n // It might be a module resolution like \"lib/storage\"\r\n if (normalizedRequest === relativeWithoutExt || normalizedRequest === relativeFromSrc) {\r\n return serverOnlyPath;\r\n }\r\n }\r\n } catch {\r\n // Ignore resolution errors\r\n }\r\n }\r\n \r\n return null;\r\n}\r\n\r\n/**\r\n * Create Rspack configuration for client bundle\r\n */\r\nexport async function createClientConfig(options: ClientBuildOptions): Promise<Configuration> {\r\n const { mode = \"production\" } = options;\r\n const bootstrapEntry = getBootstrapPath();\r\n const srcDir = getSrcDir();\r\n\r\n // Scan for server-only files\r\n const serverOnlyFiles = await scanServerOnlyFiles(srcDir);\r\n \r\n // Generate stub code (inline, no external file needed)\r\n const stubCode = generateServerOnlyStubCode();\r\n\r\n const entries: Record<string, string> = {\r\n main: bootstrapEntry,\r\n };\r\n\r\n return {\r\n mode,\r\n entry: entries,\r\n output: {\r\n path: getClientDir(),\r\n filename: \"[name].[contenthash].js\",\r\n chunkFilename: \"[name].[contenthash].js\",\r\n clean: true,\r\n publicPath: \"/\",\r\n },\r\n resolve: {\r\n extensions: [\".ts\", \".tsx\", \".js\", \".jsx\"],\r\n alias: {\r\n \"loly\": join(\r\n getProjectDir(),\r\n \"node_modules\",\r\n \"loly\",\r\n \"dist\",\r\n \"client.js\"\r\n ),\r\n },\r\n },\r\n externals: [\r\n \"express\",\r\n \"chokidar\",\r\n \"glob\",\r\n \"@rspack/core\",\r\n \"@rspack/cli\",\r\n \"tsx\",\r\n ({ request, contextInfo }: { request?: string; contextInfo?: any }) => {\r\n if (!request) return false;\r\n if (request.startsWith(\"node:\")) return request;\r\n if (NODE_BUILTINS.includes(request as any)) return `node:${request}`;\r\n \r\n // Check if this is a server-only module\r\n // We need to check the resolved path, but we can't here\r\n // So we'll handle this in the plugin instead\r\n return false;\r\n },\r\n ],\r\n externalsType: \"module\",\r\n module: {\r\n rules: [\r\n {\r\n test: /\\.tsx?$/,\r\n use: [\r\n {\r\n loader: \"builtin:swc-loader\",\r\n options: {\r\n jsc: {\r\n parser: {\r\n syntax: \"typescript\",\r\n tsx: true,\r\n decorators: false,\r\n dynamicImport: true,\r\n },\r\n transform: {\r\n react: {\r\n runtime: \"automatic\",\r\n importSource: \"loly-jsx\",\r\n throwIfNamespace: false,\r\n },\r\n },\r\n target: \"es2020\",\r\n },\r\n module: {\r\n type: \"es6\",\r\n },\r\n },\r\n },\r\n ],\r\n },\r\n {\r\n test: /\\.css$/,\r\n type: \"css\",\r\n },\r\n ],\r\n },\r\n optimization: {\r\n minimize: mode === \"production\",\r\n splitChunks: {\r\n chunks: \"all\",\r\n },\r\n usedExports: true,\r\n sideEffects: false, // More aggressive tree shaking - assume no side effects\r\n providedExports: true,\r\n concatenateModules: true, // Better for tree shaking\r\n removeEmptyChunks: true,\r\n mergeDuplicateChunks: true,\r\n },\r\n plugins: [\r\n {\r\n name: \"server-only-plugin\",\r\n apply(compiler: any) {\r\n compiler.hooks.normalModuleFactory.tap(\"server-only-plugin\", (factory: any) => {\r\n // Intercept module resolution BEFORE rspack processes imports\r\n factory.hooks.beforeResolve.tap(\"server-only-plugin\", (data: any) => {\r\n if (!data.request) return;\r\n \r\n const request = data.request;\r\n \r\n // Skip if it's already a data URI\r\n if (request.startsWith(\"data:\")) {\r\n return;\r\n }\r\n \r\n // Check if this request matches a server-only file\r\n const matchedFile = matchServerOnlyFile(request, serverOnlyFiles, srcDir);\r\n \r\n if (matchedFile) {\r\n // Replace the request with a data URI containing the stub code\r\n // Rspack supports data: URIs, so this will work\r\n // This prevents rspack from reading the real file and processing its imports\r\n const encodedStub = Buffer.from(stubCode.trim()).toString(\"base64\");\r\n data.request = `data:text/javascript;base64,${encodedStub}`;\r\n }\r\n });\r\n });\r\n },\r\n },\r\n {\r\n name: \"manifest-plugin\",\r\n apply(compiler: any) {\r\n compiler.hooks.emit.tap(\"manifest-plugin\", (compilation: any) => {\r\n const manifest: Record<string, any> = {};\r\n\r\n const entrypoints = compilation.entrypoints || new Map();\r\n const entryChunkNames = new Set<string>();\r\n for (const [name, entrypoint] of entrypoints) {\r\n entryChunkNames.add(name);\r\n const chunks = entrypoint.chunks || [];\r\n for (const chunk of chunks) {\r\n const chunkName = chunk.name || chunk.id || \"unknown\";\r\n entryChunkNames.add(chunkName);\r\n }\r\n }\r\n\r\n const chunks = compilation.chunks || [];\r\n for (const chunk of chunks) {\r\n const name = chunk.name || chunk.id || \"unknown\";\r\n const files: string[] = [];\r\n const cssFiles: string[] = [];\r\n\r\n const chunkFiles = chunk.files || [];\r\n for (const file of chunkFiles) {\r\n if (file.endsWith(\".css\")) {\r\n cssFiles.push(file);\r\n } else {\r\n files.push(file);\r\n }\r\n }\r\n\r\n const isEntry =\r\n entryChunkNames.has(name) ||\r\n (chunk.hasEntryModule && chunk.hasEntryModule()) ||\r\n name === \"main\";\r\n\r\n manifest[name] = {\r\n file: files[0] || \"\",\r\n isEntry,\r\n imports: [],\r\n css: cssFiles.length > 0 ? cssFiles : undefined,\r\n };\r\n }\r\n\r\n const manifestJson = JSON.stringify(manifest, null, 2);\r\n compilation.emitAsset(\"manifest.json\", {\r\n source: () => manifestJson,\r\n size: () => Buffer.byteLength(manifestJson, \"utf8\"),\r\n });\r\n });\r\n },\r\n },\r\n ],\r\n devtool: mode === \"production\" ? false : \"source-map\",\r\n };\r\n}\r\n","import { readFileSync } from \"fs\";\r\nimport { glob } from \"glob\";\r\nimport { normalize } from \"path\";\r\n\r\n/**\r\n * Detect if a file has \"use server\" directive at the top\r\n * The directive must be the first statement (before any imports or comments)\r\n */\r\nexport function hasUseServerDirective(filePath: string): boolean {\r\n try {\r\n const content = readFileSync(filePath, \"utf-8\");\r\n const trimmed = content.trim();\r\n \r\n // Check for \"use server\" or 'use server' as the first statement\r\n // Allow for optional semicolon\r\n return (\r\n trimmed.startsWith('\"use server\"') ||\r\n trimmed.startsWith(\"'use server'\") ||\r\n trimmed.startsWith('\"use server\";') ||\r\n trimmed.startsWith(\"'use server';\")\r\n );\r\n } catch {\r\n // If file can't be read, assume it doesn't have the directive\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Scan all TypeScript/JavaScript files in src/ to find files with \"use server\" directive\r\n * Returns a Set of absolute file paths that should be excluded from client bundle\r\n */\r\nexport async function scanServerOnlyFiles(srcDir: string): Promise<Set<string>> {\r\n const serverOnlyFiles = new Set<string>();\r\n \r\n if (!srcDir) {\r\n return serverOnlyFiles;\r\n }\r\n\r\n try {\r\n // Scan all .ts, .tsx, .js, .jsx files in src/\r\n const patterns = [\"**/*.{ts,tsx,js,jsx}\"];\r\n const files = await glob(patterns, {\r\n cwd: srcDir,\r\n absolute: true,\r\n ignore: [\"**/node_modules/**\", \"**/.loly/**\", \"**/dist/**\", \"**/.next/**\"],\r\n });\r\n\r\n for (const file of files) {\r\n if (hasUseServerDirective(file)) {\r\n // Store absolute path, normalized for cross-platform compatibility\r\n const normalizedPath = normalize(file);\r\n serverOnlyFiles.add(normalizedPath);\r\n }\r\n }\r\n } catch (error) {\r\n // If scanning fails, log warning but don't break the build\r\n console.warn(\"[loly-core] Failed to scan for server-only files:\", error);\r\n }\r\n\r\n return serverOnlyFiles;\r\n}\r\n\r\n","import { join } from \"path\";\r\nimport { existsSync, readdirSync } from \"fs\";\r\nimport { getAppDir, getServerOutDir } from \"../context\";\r\nimport { ROUTE_FILE_NAMES, NODE_BUILTINS } from \"../constants\";\r\n\r\nexport interface ServerBuildOptions {\r\n projectDir: string;\r\n outDir?: string;\r\n mode?: \"development\" | \"production\";\r\n}\r\n\r\n\r\n/**\r\n * Collect only route files from src/app/ directory\r\n * Components, lib, types are included automatically via bundling\r\n */\r\nfunction collectAppSources(appDir: string): string[] {\r\n const entries: string[] = [];\r\n\r\n function walk(dir: string) {\r\n if (!existsSync(dir)) return;\r\n\r\n const items = readdirSync(dir, { withFileTypes: true });\r\n\r\n for (const item of items) {\r\n const full = join(dir, item.name);\r\n\r\n if (item.isDirectory()) {\r\n if (item.name === \"node_modules\" || item.name.startsWith(\".\")) {\r\n continue;\r\n }\r\n walk(full);\r\n continue;\r\n }\r\n\r\n if (item.isFile()) {\r\n // Only compile route files, not components/lib/types\r\n const isRouteFile = ROUTE_FILE_NAMES.some(\r\n (routeFile) => item.name === routeFile\r\n );\r\n if (isRouteFile && (full.endsWith(\".ts\") || full.endsWith(\".tsx\"))) {\r\n if (full.endsWith(\".d.ts\")) continue;\r\n entries.push(full);\r\n }\r\n }\r\n }\r\n }\r\n\r\n walk(appDir);\r\n return entries;\r\n}\r\n\r\n\r\n/**\r\n * Build server files using esbuild\r\n */\r\nexport async function buildServerFiles(options: ServerBuildOptions): Promise<void> {\r\n const { mode = \"production\" } = options;\r\n const appDir = getAppDir();\r\n const serverOutDir = getServerOutDir();\r\n\r\n // Clean output directory\r\n if (existsSync(serverOutDir)) {\r\n const { rmSync } = await import(\"fs\");\r\n rmSync(serverOutDir, { recursive: true, force: true });\r\n }\r\n\r\n // Collect all source files\r\n const entryPoints = collectAppSources(appDir);\r\n\r\n if (entryPoints.length === 0) {\r\n return;\r\n }\r\n\r\n // Build all files at once with bundling enabled\r\n // This resolves relative imports automatically\r\n try {\r\n const { build } = await import(\"esbuild\");\r\n await build({\r\n entryPoints,\r\n outdir: serverOutDir,\r\n outbase: appDir, // Preserve directory structure\r\n format: \"esm\",\r\n platform: \"node\",\r\n target: \"es2020\",\r\n bundle: true, // Bundle to resolve relative imports\r\n packages: \"external\", // Externalize node_modules packages\r\n external: [\r\n // Explicitly externalize loly-jsx to avoid bundling it\r\n \"loly-jsx\",\r\n \"loly-jsx/*\",\r\n \"loly-jsx/jsx-runtime\",\r\n \"loly-jsx/render/*\",\r\n \"loly-jsx/router\",\r\n ],\r\n sourcemap: true,\r\n jsx: \"automatic\",\r\n jsxImportSource: \"loly-jsx\",\r\n logLevel: mode === \"production\" ? \"warning\" : \"info\",\r\n });\r\n } catch (error) {\r\n console.error(`[loly-core] Failed to build server files:`, error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Legacy function for compatibility (deprecated, use buildServerFiles instead)\r\n * @deprecated Use buildServerFiles instead\r\n */\r\nexport function createServerConfig(options: ServerBuildOptions): never {\r\n throw new Error(\r\n \"createServerConfig is deprecated. Use buildServerFiles instead for esbuild-based builds.\"\r\n );\r\n}\r\n","import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from \"fs\";\r\nimport { join, dirname } from \"path\";\r\nimport { pathToFileURL } from \"url\";\r\nimport { createRequire } from \"module\";\r\n\r\nexport interface ProcessCssOptions {\r\n inputPath: string;\r\n outputPath: string;\r\n projectDir: string;\r\n}\r\n\r\n/**\r\n * Process CSS file with PostCSS if available, otherwise copy as-is\r\n */\r\nexport async function processCssWithPostCSS(\r\n options: ProcessCssOptions\r\n): Promise<void> {\r\n const { inputPath, outputPath, projectDir } = options;\r\n\r\n // Check if PostCSS is available\r\n // PostCSS is an optional peerDependency, so we use dynamic import\r\n let postcss: any;\r\n try {\r\n // @ts-expect-error - PostCSS is an optional peerDependency\r\n const postcssModule = await import(\"postcss\");\r\n postcss = postcssModule.default || postcssModule;\r\n } catch {\r\n // PostCSS not available, copy file directly\r\n mkdirSync(dirname(outputPath), { recursive: true });\r\n copyFileSync(inputPath, outputPath);\r\n return;\r\n }\r\n\r\n // Find PostCSS config file\r\n const configPaths = [\r\n join(projectDir, \"postcss.config.js\"),\r\n join(projectDir, \"postcss.config.mjs\"),\r\n join(projectDir, \"postcss.config.cjs\"),\r\n ];\r\n\r\n const configPath = configPaths.find((p) => existsSync(p));\r\n if (!configPath) {\r\n // No PostCSS config, copy file directly\r\n mkdirSync(dirname(outputPath), { recursive: true });\r\n copyFileSync(inputPath, outputPath);\r\n return;\r\n }\r\n\r\n // Load PostCSS config\r\n // Convert path to file:// URL for Windows compatibility\r\n const configUrl = pathToFileURL(configPath).href;\r\n const configModule = await import(configUrl);\r\n const config = configModule.default || configModule;\r\n\r\n // Process CSS\r\n const css = readFileSync(inputPath, \"utf-8\");\r\n let plugins = config.plugins || [];\r\n \r\n // Create a require function that resolves modules from the project directory\r\n // This allows us to load plugins installed in the user's project\r\n const projectRequire = createRequire(join(projectDir, \"package.json\"));\r\n \r\n // Convert object plugins to array format (PostCSS config can use both)\r\n if (plugins && typeof plugins === \"object\" && !Array.isArray(plugins)) {\r\n const pluginArray = [];\r\n for (const [name, options] of Object.entries(plugins)) {\r\n try {\r\n // Resolve the plugin module path from the project directory\r\n const pluginPath = projectRequire.resolve(name);\r\n // Convert to file:// URL for ESM import\r\n const pluginUrl = pathToFileURL(pluginPath).href;\r\n // @ts-expect-error - Plugins are installed by user\r\n const pluginModule = await import(pluginUrl);\r\n const plugin = pluginModule.default || pluginModule;\r\n const pluginOptions = options && typeof options === \"object\" && Object.keys(options).length > 0 \r\n ? options \r\n : undefined;\r\n pluginArray.push(pluginOptions ? plugin(pluginOptions) : plugin());\r\n } catch (err) {\r\n console.warn(`[loly-core] Failed to load PostCSS plugin \"${name}\":`, err);\r\n throw err;\r\n }\r\n }\r\n plugins = pluginArray;\r\n }\r\n\r\n const result = await postcss(plugins).process(css, {\r\n from: inputPath,\r\n to: outputPath,\r\n });\r\n\r\n // Ensure output directory exists\r\n mkdirSync(dirname(outputPath), { recursive: true });\r\n\r\n // Write processed CSS\r\n writeFileSync(outputPath, result.css);\r\n\r\n // Write source map if available\r\n if (result.map) {\r\n writeFileSync(outputPath + \".map\", result.map.toString());\r\n }\r\n}\r\n\r\n","import type { VChild } from \"loly-jsx\";\r\nimport { SERVER } from \"../../../constants/server\";\r\n\r\n/**\r\n * Image component props\r\n */\r\nexport interface ImageProps {\r\n src: string;\r\n alt: string;\r\n width?: number;\r\n height?: number;\r\n priority?: boolean;\r\n fill?: boolean;\r\n sizes?: string;\r\n placeholder?: \"blur\" | \"empty\";\r\n blurDataURL?: string;\r\n quality?: number;\r\n format?: \"webp\" | \"avif\" | \"auto\";\r\n className?: string;\r\n style?: Record<string, string | number> | string;\r\n // Device sizes for srcset generation (defaults if not provided)\r\n deviceSizes?: number[];\r\n // Image sizes for srcset generation (defaults if not provided)\r\n imageSizes?: number[];\r\n // Additional HTML attributes\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * Generates an optimized image URL.\r\n */\r\nfunction getOptimizedImageUrl(\r\n src: string,\r\n width?: number,\r\n height?: number,\r\n quality?: number,\r\n format?: \"webp\" | \"avif\" | \"auto\"\r\n): string {\r\n const params = new URLSearchParams();\r\n params.set(\"src\", src);\r\n\r\n if (width) params.set(\"w\", width.toString());\r\n if (height) params.set(\"h\", height.toString());\r\n if (quality) params.set(\"q\", quality.toString());\r\n if (format && format !== \"auto\") params.set(\"format\", format);\r\n\r\n return `${SERVER.IMAGE_ENDPOINT}?${params.toString()}`;\r\n}\r\n\r\n/**\r\n * Generates srcset for responsive images.\r\n */\r\nfunction generateSrcSet(\r\n src: string,\r\n sizes: number[],\r\n height?: number,\r\n quality?: number,\r\n format?: \"webp\" | \"avif\" | \"auto\"\r\n): string {\r\n return sizes\r\n .map((size) => {\r\n const url = getOptimizedImageUrl(src, size, height, quality, format);\r\n return `${url} ${size}w`;\r\n })\r\n .join(\", \");\r\n}\r\n\r\n/**\r\n * Image component with automatic optimization, lazy loading, and responsive images.\r\n *\r\n * Features:\r\n * - Automatic image optimization via /_loly/image endpoint\r\n * - Lazy loading by default (unless priority is true)\r\n * - Responsive images with srcset\r\n * - Placeholder support (blur)\r\n * - Fill mode for container-filling images\r\n *\r\n * @param props - Image component props\r\n * @returns Image element\r\n */\r\nexport function Image({\r\n src,\r\n alt,\r\n width,\r\n height,\r\n priority = false,\r\n fill = false,\r\n sizes,\r\n placeholder,\r\n blurDataURL,\r\n quality,\r\n format,\r\n className,\r\n deviceSizes,\r\n imageSizes,\r\n style,\r\n ...rest\r\n}: ImageProps): VChild {\r\n // Default device sizes (matching Next.js defaults)\r\n const defaultDeviceSizes = deviceSizes || [640, 750, 828, 1080, 1200, 1920, 2048, 3840];\r\n const defaultImageSizes = imageSizes || [16, 32, 48, 64, 96, 128, 256, 384];\r\n\r\n // Validate props\r\n if (!fill && (!width || !height)) {\r\n if (typeof process !== \"undefined\" && process.env?.NODE_ENV === \"development\") {\r\n console.warn(\r\n \"[Image] width and height are required when fill is false. \" +\r\n \"This helps prevent layout shift (CLS).\"\r\n );\r\n }\r\n }\r\n\r\n // Generate optimized image URL\r\n const optimizedSrc = getOptimizedImageUrl(src, width, height, quality, format);\r\n\r\n // Generate srcset for responsive images\r\n // Use deviceSizes if width is provided, otherwise use imageSizes\r\n const srcSetSizes = width\r\n ? defaultDeviceSizes.filter((s) => s <= (width * 2))\r\n : defaultImageSizes;\r\n const srcSet =\r\n srcSetSizes.length > 0\r\n ? generateSrcSet(src, srcSetSizes, height, quality, format)\r\n : undefined;\r\n\r\n // Build styles - loly-jsx accepts style objects directly\r\n const imageStyle: Record<string, string | number> =\r\n typeof style === \"string\" ? {} : { ...(style || {}) };\r\n\r\n if (fill) {\r\n imageStyle.position = \"absolute\";\r\n imageStyle.height = \"100%\";\r\n imageStyle.width = \"100%\";\r\n imageStyle.objectFit = \"cover\";\r\n imageStyle.objectPosition = \"center\";\r\n imageStyle.top = 0;\r\n imageStyle.left = 0;\r\n } else {\r\n if (width) imageStyle.width = width;\r\n if (height) imageStyle.height = height;\r\n }\r\n\r\n // Aspect ratio container to prevent CLS (only if width and height are provided)\r\n if (!fill && width && height) {\r\n const aspectRatio = (height / width) * 100;\r\n const containerStyle: Record<string, string | number> = {\r\n display: \"block\",\r\n position: \"relative\",\r\n width: width,\r\n maxWidth: \"100%\",\r\n };\r\n const spacerStyle: Record<string, string> = {\r\n display: \"block\",\r\n paddingBottom: `${aspectRatio}%`,\r\n };\r\n\r\n return (\r\n <span style={containerStyle} className={className}>\r\n <span style={spacerStyle} />\r\n {placeholder === \"blur\" && blurDataURL && (\r\n <img\r\n src={blurDataURL}\r\n alt=\"\"\r\n aria-hidden=\"true\"\r\n style={{\r\n position: \"absolute\",\r\n top: 0,\r\n left: 0,\r\n width: \"100%\",\r\n height: \"100%\",\r\n objectFit: \"cover\",\r\n filter: \"blur(20px)\",\r\n transform: \"scale(1.1)\",\r\n }}\r\n />\r\n )}\r\n <img\r\n src={optimizedSrc}\r\n alt={alt}\r\n width={width}\r\n height={height}\r\n srcSet={srcSet}\r\n sizes={sizes}\r\n loading={priority ? \"eager\" : \"lazy\"}\r\n decoding=\"async\"\r\n style={{\r\n ...imageStyle,\r\n position: \"absolute\",\r\n top: 0,\r\n left: 0,\r\n height: \"100%\",\r\n width: \"100%\",\r\n }}\r\n {...rest}\r\n />\r\n </span>\r\n );\r\n }\r\n\r\n // Simple case without aspect ratio container\r\n // Handle style prop - can be string or object\r\n const finalStyle =\r\n typeof style === \"string\" ? style : imageStyle;\r\n\r\n return (\r\n <img\r\n src={optimizedSrc}\r\n alt={alt}\r\n width={width}\r\n height={height}\r\n srcSet={srcSet}\r\n sizes={sizes}\r\n loading={priority ? \"eager\" : \"lazy\"}\r\n decoding=\"async\"\r\n className={className}\r\n style={finalStyle}\r\n {...rest}\r\n />\r\n );\r\n}\r\n\r\n"],"mappings":"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","names":["path","path","path","path","loadComponent","join","existsSync","resolve","existsSync","resolve","existsSync","resolve","join","join","existsSync","existsSync","routeFactory","route","resolve","renderToString","express","existsSync","crypto","fs","path","path","path","path","path","fs","metadata","crypto","matchRoutePattern","HTTP_METHODS","existsSync","express","getRouteConfig","join","existsSync","join","existsSync","readFileSync","existsSync","readFileSync","join","matchRoutePattern","normalizePath","path","normalizePath","route","resolve","loadComponent","join","existsSync","existsSync","readFileSync","join","dirname","relative","relative","join","existsSync","readFileSync","path","writeFileSync","dirname","generateAssetTags","join","normalize","relative","readFileSync","glob","normalize","relative","join","chunks","join","existsSync","existsSync","join","existsSync","readFileSync","writeFileSync","mkdirSync","join","dirname","options","join","existsSync","routeConfig","resolve"]}
|