{"version":3,"sources":["../src/nitro/index.ts"],"sourcesContent":["import type { NitroConfig } from \"nitro/config\";\nimport type { ResolvedFarmConfig } from \"../config\";\nimport type { RouteManager } from \"../routing/route-manager\";\nimport type { APIRouteManager } from \"../api/route-manager\";\nimport type { ServerRenderer } from \"../server/renderer\";\nimport { createNitroAPIHandler } from \"./api-handler\";\nimport { createNitroSSRHandler } from \"./ssr-handler\";\nimport path from \"path\";\nimport { prepareFarmWorkflowsForNitro } from \"../workflows\";\nimport {\n  createFarmCronCloudflareConfig,\n  mergeScheduledTasks,\n  prepareFarmCronForNitro,\n} from \"../cron\";\nimport { routeRulesToNitroRouteRules } from \"../route-rules\";\nimport { resolveFarmAPIServerBasePath } from \"../api/server-path\";\n\n/**\n * Create Nitro configuration for Farm.js\n * Based on https://nitro.build/config\n */\nexport async function createNitroConfig(\n  config: ResolvedFarmConfig,\n  routeManager: RouteManager,\n  apiRouteManager: APIRouteManager,\n  serverRenderer: ServerRenderer,\n  preset = \"node-server\",\n): Promise<NitroConfig> {\n  const root = config.root || process.cwd();\n  const apiBasePath = resolveFarmAPIServerBasePath(config.api);\n  const srcDir = config.srcDir || \"src\";\n  const distDir = \".farm\";\n  // Nitro build directory - where Nitro does its work (temporary)\n  // We use .nitro as a working directory, but ensure output goes to .farm/.output\n  const nitroBuildDir = path.join(root, distDir, \".nitro\");\n  // Final output directory - where the deployable output goes\n  // This MUST be .farm/.output (not .nitro/.output) for consistency\n  const outputDir = path.join(root, distDir, \".output\");\n  // Server directory for handlers (inside build dir, will be copied to output)\n  const serverDir = path.join(nitroBuildDir, \"server\");\n\n  // Ensure Nitro doesn't create its own .output inside .nitro\n  // By explicitly setting output.dir, Nitro will use our specified directory\n\n  // Create server directory structure for Nitro to discover routes\n  // According to Nitro docs: https://nitro.build/deploy/providers/vercel\n  // Routes should be in server/api/[...].ts and server/routes/[...].ts\n  const { mkdir, writeFile } = await import(\"fs/promises\");\n  await mkdir(serverDir, { recursive: true });\n  await mkdir(path.join(serverDir, \"api\"), { recursive: true });\n  await mkdir(path.join(serverDir, \"routes\"), { recursive: true });\n  const farmWorkflows = await prepareFarmWorkflowsForNitro({\n    ...config,\n    distDir,\n  });\n  const farmCron = await prepareFarmCronForNitro({\n    ...config,\n    distDir,\n  });\n  const scheduledTasks = mergeScheduledTasks(farmWorkflows.scheduledTasks, farmCron.scheduledTasks);\n  const cloudflareCronConfig = createFarmCronCloudflareConfig(farmCron.jobs);\n\n  // Create a runtime registry file to store route managers\n  // This will be populated at runtime through Nitro hooks\n  const registryFile = path.join(serverDir, \"farm-registry.ts\");\n\n  // Serialize route paths for SSR module loading\n  const routePaths: Record<string, string> = {};\n  for (const [pattern, entry] of routeManager.getRoutes()) {\n    const bundledPath = entry.modulePath\n      .replace(/.*\\/src\\/app\\//, \"\")\n      .replace(/\\.(tsx?|jsx?)$/, \".js\");\n    routePaths[pattern] = bundledPath;\n  }\n\n  // Load client manifest path for reference\n  const clientManifestPath = path.join(root, distDir, \"client\", \"farm-client-manifest.json\");\n\n  await writeFile(\n    registryFile,\n    `\n// Auto-generated by Farm.js\n// Runtime registry for route managers and renderers\nexport const farmRegistry: {\n  apiRouteManager?: any;\n  routeManager?: any;\n  serverRenderer?: any;\n  env?: any;\n  deploymentId?: string;\n  basePath?: string;\n  apiBasePath?: string;\n  clientManifest?: any;\n  routePaths?: Record<string, string>;\n} = {\n  env: ${JSON.stringify(config.env || { server: {}, public: {} }, null, 2)},\n  deploymentId: ${JSON.stringify(config.deploymentId)},\n  basePath: ${JSON.stringify(config.basePath)},\n  apiBasePath: ${JSON.stringify(apiBasePath)},\n  routePaths: ${JSON.stringify(routePaths, null, 2)},\n};\n`,\n    \"utf-8\",\n  );\n\n  // Create API route handler file\n  // For Vercel, Nitro expects routes in server/api/[...].ts format\n  // This catch-all will handle all /api/* requests\n  const apiHandlerFile = path.join(serverDir, \"api\", \"[...].ts\");\n  await mkdir(path.dirname(apiHandlerFile), { recursive: true });\n  await writeFile(\n    apiHandlerFile,\n    `\n// Auto-generated by Farm.js\n// This handler intercepts all /api/* requests\nimport { defineEventHandler, getHeaders, readRawBody, sendWebResponse, setResponseStatus, getRequestURL } from 'h3';\nimport type { H3Event } from 'h3';\nimport { farmRegistry } from '../farm-registry';\nimport { createFarmLegacyRequest } from '@farm.js/core/internal/production-runtime';\n\nexport default defineEventHandler(async (event: H3Event) => {\n  // Get URL using H3's abstraction (works in all environments)\n  const url = getRequestURL(event);\n  const urlPath = url.pathname;\n  const apiBasePath = farmRegistry.apiBasePath || '/api';\n  const isAPIPath = apiBasePath !== '/' &&\n    (urlPath === apiBasePath || urlPath.startsWith(apiBasePath + '/'));\n  \n  // Only handle API routes - for Vercel, Nitro routes /api/* to this handler\n  // According to https://nitro.build/deploy/providers/vercel\n  // This handler should process all /api/* routes\n  if (!isAPIPath) {\n    // Return undefined to let Nitro's routing system handle non-API routes\n    return undefined;\n  }\n  \n  // Ensure registry is populated (lazy initialization)\n  // In serverless environments, the registry needs to be initialized at runtime\n  if (!farmRegistry.apiRouteManager) {\n    // Try to initialize from global if available (set during build)\n    if (typeof globalThis !== 'undefined' && (globalThis as any).__FARM_REGISTRY__) {\n      Object.assign(farmRegistry, (globalThis as any).__FARM_REGISTRY__);\n    }\n    // If still not available, try the init function (if it exists)\n    if (!farmRegistry.apiRouteManager && (farmRegistry as any).__INIT__) {\n      (farmRegistry as any).__INIT__();\n    }\n  }\n  \n  const apiRouteManager = farmRegistry.apiRouteManager;\n  if (!apiRouteManager) {\n    console.error('API route manager not initialized. Registry keys:', Object.keys(farmRegistry));\n    setResponseStatus(event, 500);\n    return { error: 'API route manager not initialized. Please check server logs.' };\n  }\n  \n  const startTime = Date.now();\n  const method = event.method || 'GET';\n  const host = url.host || 'localhost';\n  \n  // Log API request (only in development)\n  if (process.env.NODE_ENV === 'development' || !process.env.NODE_ENV) {\n    try {\n      const pc = await import('picocolors');\n      const log = [\n        pc.default.dim('[') + pc.default.bold(pc.default.blue('FARM')) + pc.default.dim(']'),\n        pc.default.dim('[') + pc.default.bold(pc.default.white(method.padEnd(3))) + pc.default.dim(']'),\n        pc.default.cyan('[API]'),\n        pc.default.gray(\\`\\${url.protocol}//\\${host}\\${urlPath}\\`),\n      ].join(' ');\n      console.log(log);\n    } catch {\n      // picocolors not available, use simple log\n      console.log(\\`[FARM] [\\${method}] [API] \\${urlPath}\\`);\n    }\n  }\n  \n  try {\n    // Convert H3 event to Web Request using H3 abstractions\n    const protocol = url.protocol.replace(':', '') || 'http';\n    const host = url.host || 'localhost';\n    const fullUrl = url.toString();\n    \n    const headers = new Headers();\n    const h3Headers = getHeaders(event);\n    \n    for (const [key, value] of Object.entries(h3Headers)) {\n      if (value) {\n        headers.set(key, Array.isArray(value) ? value.join(', ') : String(value));\n      }\n    }\n    \n    const request = await createFarmLegacyRequest(event, fullUrl, headers, readRawBody);\n    \n    // Call better-call handler\n    const betterCallHandler = apiRouteManager.getHandler();\n    if (!betterCallHandler) {\n      setResponseStatus(event, 404);\n      return { error: 'API handler not found' };\n    }\n    \n    const response = await betterCallHandler(request);\n    \n    // Log API response (only in development)\n    if (process.env.NODE_ENV === 'development' || !process.env.NODE_ENV) {\n      const duration = Date.now() - startTime;\n      const status = response.status;\n      try {\n        const pc = await import('picocolors');\n        let statusColor = pc.default.green;\n        if (status >= 500) statusColor = pc.default.red;\n        else if (status >= 400) statusColor = pc.default.yellow;\n        else if (status >= 300) statusColor = pc.default.cyan;\n\n        const log = [\n          pc.default.dim('[') + pc.default.bold(pc.default.blue('FARM')) + pc.default.dim(']'),\n          status >= 400 ? pc.default.red('✗') : pc.default.green('✓'),\n          pc.default.cyan('[API]'),\n          pc.default.gray(urlPath),\n          pc.default.dim('-'),\n          statusColor(status.toString()),\n          pc.default.dim(\\`(\\${duration}ms)\\`),\n        ].join(' ');\n        console.log(log);\n      } catch {\n        // picocolors not available, use simple log\n        console.log(\\`[FARM] [\\${method}] [API] \\${urlPath} - \\${response.status} (\\${duration}ms)\\`);\n      }\n    }\n    \n    return sendWebResponse(response);\n  } catch (error: any) {\n    console.error('API handler error:', error);\n    setResponseStatus(event, 500);\n    return {\n      error: error.message || 'Internal Server Error',\n    };\n  }\n});\n`,\n    \"utf-8\",\n  );\n\n  // Create SSR catch-all route handler\n  // For Vercel, Nitro expects routes in server/routes/[...].ts format\n  const ssrHandlerFile = path.join(serverDir, \"routes\", \"[...].ts\");\n  await mkdir(path.dirname(ssrHandlerFile), { recursive: true });\n  await writeFile(\n    ssrHandlerFile,\n    `\n// Auto-generated by Farm.js\n// This handler handles all page routes (SSR)\nimport { defineEventHandler, setResponseStatus, getRequestURL, setHeader, getHeaders, readRawBody, sendWebResponse, setCookie } from 'h3';\nimport type { H3Event } from 'h3';\nimport { farmRegistry } from '../farm-registry';\nimport React from 'react';\nimport { renderToString } from 'react-dom/server';\nimport { searchParamsToObject } from '@farm.js/core/internal/production-runtime';\nimport { createFarmLegacyRequest, renderFarmLegacyErrorHtml, renderFarmLegacyHtml } from '@farm.js/core/internal/production-runtime';\n\nexport default defineEventHandler(async (event: H3Event) => {\n  try {\n    // Ensure registry is populated (lazy initialization)\n    // In serverless environments, the registry needs to be initialized at runtime\n    if (!farmRegistry.routeManager || !farmRegistry.serverRenderer) {\n      // Try to initialize from global if available (set during build)\n      if (typeof globalThis !== 'undefined' && (globalThis as any).__FARM_REGISTRY__) {\n        Object.assign(farmRegistry, (globalThis as any).__FARM_REGISTRY__);\n      }\n      // If still not available, try the init function (if it exists)\n      if ((!farmRegistry.routeManager || !farmRegistry.serverRenderer) && (farmRegistry as any).__INIT__) {\n        (farmRegistry as any).__INIT__();\n      }\n    }\n    \n    const routeManager = farmRegistry.routeManager;\n    const serverRenderer = farmRegistry.serverRenderer;\n    \n    if (!routeManager || !serverRenderer) {\n      console.error('Route manager or renderer not initialized. Registry keys:', Object.keys(farmRegistry));\n      setResponseStatus(event, 500);\n      setHeader(event, 'Content-Type', 'text/html; charset=utf-8');\n      return '<!DOCTYPE html><html><head><title>Error</title></head><body><h1>500 Internal Server Error</h1><p>Route manager or renderer not initialized. Please check server logs.</p></body></html>';\n    }\n    \n    // Get URL from H3 event\n    const url = getRequestURL(event);\n    const pathname = url.pathname;\n    const apiBasePath = farmRegistry.apiBasePath || '/api';\n    const isAPIPath = apiBasePath !== '/' &&\n      (pathname === apiBasePath || pathname.startsWith(apiBasePath + '/'));\n    const redirectMatch = routeManager.matchRedirect(pathname, url.search);\n    if (redirectMatch) {\n      setResponseStatus(event, redirectMatch.statusCode);\n      setHeader(event, 'Location', redirectMatch.destination);\n      return \\`Redirecting to \\${redirectMatch.destination}\\`;\n    }\n    const apiRouteManager = farmRegistry.apiRouteManager;\n\n    if (apiRouteManager?.matchRoute(pathname)) {\n      const handler = apiRouteManager.getHandler();\n      if (!handler) {\n        setResponseStatus(event, 404);\n        return { error: 'API handler not found' };\n      }\n\n      const headers = new Headers();\n      const h3Headers = getHeaders(event);\n      for (const [key, value] of Object.entries(h3Headers)) {\n        if (value) {\n          headers.set(key, Array.isArray(value) ? value.join(', ') : String(value));\n        }\n      }\n\n      const request = await createFarmLegacyRequest(event, url, headers, readRawBody);\n      const response = await handler(request);\n\n      return sendWebResponse(response);\n    }\n\n    // Skip API routes - let the API handler process them\n    if (isAPIPath) {\n      // Return undefined to let Nitro's API handler process\n      return undefined;\n    }\n    \n    // Skip static assets - let Nitro serve them\n    // Only skip if it's clearly a static file (has extension and not in root)\n    if (pathname.startsWith('/assets/') || (pathname.includes('.') && !isAPIPath)) {\n      // Check if it's a static file by extension\n      const staticExtensions = ['.js', '.css', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.woff', '.woff2', '.ttf', '.eot'];\n      const hasStaticExtension = staticExtensions.some(ext => pathname.toLowerCase().endsWith(ext));\n      if (hasStaticExtension) {\n        return; // Let Nitro's static file handler process\n      }\n    }\n    \n    // Try to use Node.js req/res if available (for node-server preset)\n    if (event.node && event.node.req && event.node.res) {\n      await serverRenderer.renderPage(event.node.req as any, event.node.res as any);\n      return undefined; // Response already sent\n    }\n\n    if (farmRegistry.deploymentId) {\n      setHeader(event, 'x-farm-deployment-id', farmRegistry.deploymentId);\n      setCookie(event, '__farm_deployment', farmRegistry.deploymentId, {\n        httpOnly: true,\n        sameSite: 'lax',\n        secure: url.protocol === 'https:',\n        path: farmRegistry.basePath || '/',\n      });\n    }\n    \n    // For serverless (Vercel), render to string and send HTML\n    try {\n      // Match route\n      const { route, params, layouts } = routeManager.matchRoute(pathname);\n      \n      if (!route) {\n        setResponseStatus(event, 404);\n        setHeader(event, 'Content-Type', 'text/html; charset=utf-8');\n        return '<!DOCTYPE html><html><head><title>404 Not Found</title></head><body><h1>404 Not Found</h1></body></html>';\n      }\n      \n      // Get search params\n      const searchParamsObject = searchParamsToObject(url.searchParams);\n      \n      // Load route module - in production, use bundled SSR output\n      // Get bundled path from registry or construct it\n      let routeModule;\n      const routePaths = farmRegistry.routePaths || {};\n      const bundledPath = routePaths[pathname] || route.modulePath\n        .replace(/.*\\\\/src\\\\/app\\\\//, '')\n        .replace(/\\\\.(tsx?|jsx?)$/, '.js');\n      \n      try {\n        // Try to load from bundled SSR output (copied to Nitro's server/farm directory)\n        // Nitro bundles everything, so we need to use the correct import path\n        routeModule = await import('./farm/' + bundledPath);\n      } catch (importError) {\n        // Fallback: try route manager's load method (for node-server preset)\n        try {\n          routeModule = await routeManager.loadRouteModule(route.modulePath);\n        } catch (loadError) {\n          // Last resort: try just the filename\n          const bundledName = bundledPath.split('/').pop() || 'page.js';\n          try {\n            routeModule = await import('./farm/' + bundledName);\n          } catch {\n            throw new Error(\\`Failed to load route module: \\${route.modulePath}. Tried: ./farm/\\${bundledPath}, ./farm/\\${bundledName}\\`);\n          }\n        }\n      }\n      \n      if (!routeModule.default) {\n        throw new Error(\\`Route module \\${route.modulePath} does not export a default component\\`);\n      }\n      \n      // Load layout modules\n      const layoutModules = await Promise.all(\n        layouts.map(async (layout) => {\n          const bundledPath = layout.modulePath\n            .replace(/.*\\\\/src\\\\/app\\\\//, '')\n            .replace(/\\\\.(tsx?|jsx?)$/, '.js');\n          \n          try {\n            // Try to load from bundled SSR output\n            return await import('./farm/' + bundledPath);\n          } catch {\n            // Fallback to route manager's load method\n            try {\n              return await routeManager.loadLayoutModule(layout.modulePath);\n            } catch {\n              // Last resort: try just the filename\n              const bundledName = bundledPath.split('/').pop() || 'layout.js';\n              try {\n                return await import('./farm/' + bundledName);\n              } catch {\n                // Return a dummy layout if all fails\n                return { default: ({ children }: any) => children };\n              }\n            }\n          }\n        })\n      );\n      \n      // Create page props\n      const rawPageProps = {\n        params,\n        searchParams: Promise.resolve(searchParamsObject),\n        path: pathname,\n      };\n      const pageProps = routeModule.__farmResolveRouteProps\n        ? await routeModule.__farmResolveRouteProps(rawPageProps)\n        : (() => {\n            const routeSchemas = routeModule.__farmRouteParsesProps\n              ? {}\n              : routeModule.__farmRouteSchemas || {};\n            const parsedParams = routeSchemas.params?.parse\n              ? routeSchemas.params.parse(params)\n              : params;\n            const parsedSearch = routeSchemas.search?.parse\n              ? routeSchemas.search.parse(searchParamsObject)\n              : searchParamsObject;\n            return {\n              ...rawPageProps,\n              params: parsedParams,\n              search: parsedSearch,\n              searchParams: Promise.resolve(parsedSearch),\n            };\n          })();\n      \n      // Create page element\n      const PageComponent = routeModule.default;\n      let pageElement;\n      if (typeof PageComponent === \"function\" && PageComponent.constructor.name === \"AsyncFunction\") {\n        pageElement = await PageComponent(pageProps);\n      } else {\n        pageElement = React.createElement(PageComponent, pageProps);\n      }\n      \n      // Wrap with layouts\n      for (let i = layoutModules.length - 1; i >= 0; i--) {\n        const layoutModule = layoutModules[i];\n        const LayoutComponent = layoutModule.default;\n        pageElement = React.createElement(LayoutComponent, {\n          children: pageElement,\n          params,\n        } as any);\n      }\n      \n      // Render to string\n      const html = renderToString(pageElement);\n      \n      // Get client script path from manifest\n      const clientManifest = farmRegistry.clientManifest || {};\n      // Find the client script for this route - check manifest structure\n      let clientScript = '/assets/page-wbYjx1yQ.js'; // Default fallback\n      if (clientManifest && typeof clientManifest === 'object') {\n        // Manifest structure: { \"assets/page-xxx.js\": { ... } }\n        const manifestEntry = Object.values(clientManifest).find((entry: any) => \n          entry && entry.name === 'page'\n        ) as any;\n        if (manifestEntry && manifestEntry.chunks && manifestEntry.chunks[0]) {\n          clientScript = '/' + manifestEntry.chunks[0];\n        } else if (Object.keys(clientManifest).length > 0) {\n          // Fallback to first asset in manifest\n          clientScript = '/' + Object.keys(clientManifest)[0];\n        }\n      }\n      \n      // Build full HTML\n      const fullHtml = renderFarmLegacyHtml({\n        deploymentId: farmRegistry.deploymentId || '',\n        pageProps,\n        pathname,\n        html,\n        clientScript,\n      });\n      \n      setHeader(event, 'Content-Type', 'text/html; charset=utf-8');\n      return fullHtml;\n      \n    } catch (renderError: any) {\n      console.error('SSR render error:', renderError);\n      setResponseStatus(event, 500);\n      setHeader(event, 'Content-Type', 'text/html; charset=utf-8');\n      return renderFarmLegacyErrorHtml();\n    }\n  } catch (error: any) {\n    console.error('SSR handler error:', error);\n    setResponseStatus(event, 500);\n    setHeader(event, 'Content-Type', 'text/html; charset=utf-8');\n    return renderFarmLegacyErrorHtml();\n  }\n});\n`,\n    \"utf-8\",\n  );\n\n  // Create Nitro config according to https://nitro.build/config\n  // Compatibility date is required in Nitro v3\n  const nitroConfig: NitroConfig = {\n    preset,\n    // rootDir must be the project root for Nitro to correctly resolve paths\n    rootDir: root,\n    // srcDir should point to where source files are (for scanning)\n    // But we're using scanDirs to point to our server directory\n    srcDir: root,\n    // buildDir is where Nitro builds (temporary working directory)\n    buildDir: nitroBuildDir,\n    // output.dir is where the final deployable output goes\n    // This ensures everything ends up in .farm/.output\n    compatibilityDate: \"2024-12-01\",\n    // Vercel-specific configuration\n    ...(preset === \"vercel\"\n      ? {\n          vercel: {\n            // Ensure proper function configuration\n            config: {},\n          },\n        }\n      : {}),\n    // Tell Nitro to scan the server directory we created\n    // This ensures our handlers are discovered by Nitro\n    scanDirs: [serverDir],\n    tasks: {\n      ...farmWorkflows.tasks,\n      ...farmCron.tasks,\n    },\n    scheduledTasks,\n    ...(preset === \"cloudflare-module\" && cloudflareCronConfig\n      ? {\n          cloudflare: cloudflareCronConfig,\n        }\n      : {}),\n    handlers: farmWorkflows.handlerPath\n      ? [\n          {\n            route: `${config.workflows.route}/**`,\n            handler: farmWorkflows.handlerPath,\n          },\n        ]\n      : [],\n    // Route rules for Vercel\n    routeRules: {\n      ...(apiBasePath === \"/\"\n        ? {}\n        : {\n            [`${apiBasePath}/**`]: {\n              cors: true,\n              headers: {\n                \"Access-Control-Allow-Origin\": \"*\",\n                \"Access-Control-Allow-Methods\": \"*\",\n                \"Access-Control-Allow-Headers\": \"*\",\n              },\n            },\n          }),\n      \"/**\": {\n        prerender: false,\n      },\n      ...routeRulesToNitroRouteRules(config.routeRules),\n    },\n\n    // // Exclude certain directories from scanning\n    // scanDirsExclude: [\n    //   '**/node_modules/**',\n    //   '**/.git/**',\n    //   '**/.output/**',\n    //   '**/.nitro/**',\n    // ],\n    output: {\n      // CRITICAL: All output MUST go to .farm/.output (NOT .nitro/.output)\n      // This ensures consistency and that deployment always uses .farm/.output\n      // By explicitly setting dir, serverDir, and publicDir, we prevent Nitro\n      // from creating its own .output directory inside .nitro\n      dir: outputDir, // .farm/.output\n      serverDir: path.join(outputDir, \"server\"), // .farm/.output/server\n      publicDir: path.join(outputDir, \"public\"), // .farm/.output/public\n    },\n    // Use Nitro hooks to populate the runtime registry\n    // This allows us to pass complex objects (route managers, renderers) at runtime\n    hooks: {\n      \"build:before\": async (nitro: any) => {\n        // Import and populate the registry at build time\n        const registryPath = path.join(serverDir, \"farm-registry.ts\");\n        const { farmRegistry } = await import(/* @vite-ignore */ registryPath);\n\n        // Store route paths (serializable)\n        const routePaths: Record<string, string> = {};\n        for (const [pattern, entry] of routeManager.getRoutes()) {\n          const bundledPath = entry.modulePath\n            .replace(/.*\\/src\\/app\\//, \"\")\n            .replace(/\\.(tsx?|jsx?)$/, \".js\");\n          routePaths[pattern] = bundledPath;\n        }\n        farmRegistry.routePaths = routePaths;\n\n        // Load and store client manifest for SSR\n        try {\n          const clientManifestPath = path.join(\n            root,\n            distDir,\n            \"client\",\n            \"farm-client-manifest.json\",\n          );\n          const { readFile } = await import(\"fs/promises\");\n          const manifestContent = await readFile(clientManifestPath, \"utf-8\");\n          farmRegistry.clientManifest = JSON.parse(manifestContent);\n        } catch (error) {\n          // Manifest not critical, continue without it\n          farmRegistry.clientManifest = {};\n        }\n\n        // CRITICAL: Store managers in a way that persists to runtime\n        // In serverless, we can't serialize complex objects, so we store them\n        // in a module-level variable that will be available at runtime\n        // The handlers will access them through the registry\n        // We use a closure to capture the managers\n        (farmRegistry as any).__INIT__ = () => {\n          farmRegistry.apiRouteManager = apiRouteManager;\n          farmRegistry.routeManager = routeManager;\n          farmRegistry.serverRenderer = serverRenderer;\n          farmRegistry.env = config.env || { server: {}, public: {} };\n          farmRegistry.deploymentId = config.deploymentId;\n          farmRegistry.basePath = config.basePath;\n        };\n\n        // Also store in global for runtime access (works in serverless)\n        // This ensures they're available even if module state is reset\n        if (typeof globalThis !== \"undefined\") {\n          (globalThis as any).__FARM_REGISTRY__ = {\n            apiRouteManager,\n            routeManager,\n            serverRenderer,\n            env: farmRegistry.env,\n            deploymentId: farmRegistry.deploymentId,\n            basePath: farmRegistry.basePath,\n            clientManifest: farmRegistry.clientManifest,\n            routePaths: farmRegistry.routePaths,\n          };\n        }\n      },\n    },\n    // API base URL (default is /api)\n    apiBaseURL: \"/api\",\n    // Include public directory and client build\n    publicAssets: [\n      {\n        baseURL: \"/\",\n        dir: path.join(root, \"public\"),\n      },\n      // Include client build assets\n      {\n        baseURL: \"/\",\n        dir: path.join(root, distDir, \"client\"),\n      },\n    ],\n    // Build configuration\n    minify: process.env.NODE_ENV === \"production\",\n    sourceMap: true,\n    // Bundle all dependencies to avoid workspace issues on Vercel\n    // This ensures all farm package code is bundled into the serverless function\n    // so it doesn't need to resolve workspace dependencies at runtime\n    // This is similar to how Next.js and Nuxt bundle their core packages\n    // bundle: true,\n    // External dependencies that should NOT be bundled (provided by runtime)\n    // We exclude React/ReactDOM to reduce bundle size (they're in node_modules)\n    externals: {\n      external: [\"react\", \"react-dom\"],\n      // Keep React external - it's in the serverless function's node_modules\n      // This reduces bundle size significantly\n    },\n    // Runtime config\n    runtimeConfig: {\n      public: {},\n    },\n    // Experimental features\n    experimental: {\n      tasks: farmWorkflows.workflows.length > 0 || farmCron.jobs.length > 0,\n      wasm: false, // Disable for now to avoid issues\n    },\n  };\n\n  return nitroConfig;\n}\n\n/**\n * Get Nitro preset from config\n */\nexport function getNitroPreset(preset?: string): string {\n  return preset || \"node-server\";\n}\n"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":["routePaths","clientManifestPath"]}