{"version":3,"file":"createSsrServerlessFunction.js","names":[],"sources":["esm/vercel/build/generate/createSsrServerlessFunction.js"],"sourcesContent":["import { join, resolve } from \"node:path\";\nimport fs from \"fs-extra\";\nimport { serverlessVercelNodeJsConfig } from \"../config/vc-config-base\";\nimport { serverlessVercelPackageJson } from \"../config/vc-package-base\";\nimport { getPathFromRoute } from \"../getPathFromRoute\";\nasync function createSsrServerlessFunction(route, buildInfo, oneOptionsRoot, postBuildLogs) {\n  try {\n    const path = getPathFromRoute(route, { includeIndex: true });\n    postBuildLogs.push(`[one.build][vercel.createSsrServerlessFunction] path: ${path}`);\n    const buildInfoAsString = JSON.stringify(buildInfo);\n    const funcFolder = resolve(\n      join(oneOptionsRoot, `.vercel/output/functions/${path}.func`)\n    );\n    await fs.ensureDir(funcFolder);\n    const outDir = buildInfo.outDir || \"dist\";\n    const distServerFrom = resolve(join(oneOptionsRoot, outDir, \"server\"));\n    const distServerTo = resolve(join(funcFolder, \"server\"));\n    await fs.ensureDir(distServerTo);\n    postBuildLogs.push(\n      `[one.build][vercel.createSsrServerlessFunction] copy server dist files from ${distServerFrom} to ${distServerTo}`\n    );\n    await fs.copy(distServerFrom, distServerTo);\n    postBuildLogs.push(\n      `[one.build][vercel.createSsrServerlessFunction] writing buildInfo.json`\n    );\n    await fs.writeFile(\n      join(funcFolder, \"buildInfo.js\"),\n      `export default ${buildInfoAsString}`\n    );\n    await fs.ensureDir(join(funcFolder, \"entrypoint\"));\n    const entrypointFilePath = resolve(join(funcFolder, \"entrypoint\", \"index.js\"));\n    postBuildLogs.push(\n      `[one.build][vercel.createSsrServerlessFunction] writing entrypoint to ${entrypointFilePath}`\n    );\n    await fs.writeFile(\n      entrypointFilePath,\n      `\n  const buildInfoConfig = await import('../buildInfo.js');\n  const entry = await import('../server/_virtual_one-entry.js');\n  const routeFile = ${JSON.stringify(route.file)}\n\n  const handler = async (req, res) => {\n    // console.debug(\"req.url\", req.url);\n    const url = new URL(req.url, \\`https://\\${process.env.VERCEL_URL}\\`);\n\n    // Check if this is a loader request (routed here by config.json rewrite)\n    const isLoaderRequest = url.searchParams.get('__loader') === '1';\n\n    // Extract route params - from URL path match OR from query params (for loader requests)\n    const routePattern = ${JSON.stringify(route.page)};\n    const paramNames = [];\n    const regexPattern = routePattern\n      .replace(/\\\\[\\\\.\\\\.\\\\.(\\\\w+)\\\\]/g, (_, name) => { paramNames.push({ name, catch: true }); return '(.+)'; })\n      .replace(/\\\\[(\\\\w+)\\\\]/g, (_, name) => { paramNames.push({ name, catch: false }); return '([^/]+)'; });\n\n    const routeParams = {};\n\n    // First try to get params from query string (set by Vercel rewrite rules)\n    // This handles both loader requests and regular page requests that went through rewrites\n    for (const param of paramNames) {\n      const value = url.searchParams.get(param.name);\n      if (value) {\n        routeParams[param.name] = param.catch ? value.split('/') : value;\n      }\n    }\n\n    // If no params found in query string, try extracting from URL path\n    if (Object.keys(routeParams).length === 0) {\n      const match = url.pathname.match(new RegExp(\\`^\\${regexPattern}$\\`));\n      if (match) {\n        paramNames.forEach((param, index) => {\n          const value = match[index + 1];\n          routeParams[param.name] = param.catch ? value.split('/') : value;\n        });\n      }\n    }\n\n    // Create a proper Request object for SSR loaders\n    const request = new Request(url.toString(), {\n      method: req.method || 'GET',\n      headers: new Headers(req.headers || {}),\n    });\n\n    // Reconstruct the original path by replacing [param] placeholders with actual values\n    // The pathname might be the rewritten path (e.g., /dynamic/[id] instead of /dynamic/123)\n    let originalPath = url.pathname;\n    for (const [key, value] of Object.entries(routeParams)) {\n      originalPath = originalPath.replace(\n        new RegExp(\\`(\\\\\\\\[|%5B)(\\\\\\\\.\\\\\\\\.\\\\\\\\.)?\\${key}(\\\\\\\\]|%5D)\\`, 'i'),\n        () => (Array.isArray(value) ? value.join('/') : value)\n      );\n    }\n\n    const host = url.hostname;\n    let subdomain;\n    if (host && host !== 'localhost' && !/^\\\\d+\\\\.\\\\d+\\\\.\\\\d+\\\\.\\\\d+$/.test(host)) {\n      const parts = host.split('.');\n      if (parts.length >= 3) subdomain = parts.slice(0, -2).join('.');\n    }\n\n    const loaderProps = {\n      path: originalPath,\n      params: routeParams,\n      subdomain,\n      request,\n    }\n\n    const postfix = url.pathname.endsWith('/') ? 'index.tsx' : '+ssr.tsx';\n    // const routeFile = \\`.\\${url.pathname}\\${postfix}\\`;\n    let route = buildInfoConfig.default.routeToBuildInfo[routeFile];\n\n    // If we cannot find the route by direct match, try to find it by looking it up in the\n    // pathToRoute mapping. Currently this handles cases such as \"(some-group)/index.tsx\",\n    // \"index.web.tsx\".\n    if (!route) {\n      const routeName = buildInfoConfig.default.pathToRoute[url.pathname];\n      route = buildInfoConfig.default.routeToBuildInfo[routeName];\n    }\n\n    const exported = await import(route.serverJsPath.replace('${outDir}/','../'))\n    const loaderData = await exported.loader?.(loaderProps)\n\n    // For loader requests, return the loader data as a JavaScript module\n    if (isLoaderRequest) {\n      res.setHeader('Content-Type', 'application/javascript; charset=utf-8')\n      res.setHeader('Cache-Control', 'no-store')\n      res.end(\\`export function loader() { return \\${JSON.stringify(loaderData)} }\\`)\n      return\n    }\n\n    // For page requests, render the full HTML\n    const render = entry.default.render;\n    const preloads = route.preloads\n    const css = route.css || []\n    const rendered = await render({\n      mode: route.type,\n      loaderData,\n      loaderProps,\n      path: loaderProps?.path || '/',\n      preloads,\n      css,\n    })\n    res.setHeader('Content-Type', 'text/html; charset=utf-8')\n    // https://vercel.com/docs/deployments/skew-protection#supported-frameworks__\n    if (process.env.VERCEL_SKEW_PROTECTION_ENABLED === '1') {\n      res.setHeader('Set-Cookie', [\n        \\`__vdpl=\\${process.env.VERCEL_DEPLOYMENT_ID}; HttpOnly\\`,\n      ]);\n    }\n    res.end(rendered)\n  }\n\n  export default handler;\n  `\n    );\n    const packageJsonFilePath = resolve(join(funcFolder, \"package.json\"));\n    postBuildLogs.push(\n      `[one.build][vercel.createSsrServerlessFunction] writing package.json to ${packageJsonFilePath}`\n    );\n    await fs.writeJSON(packageJsonFilePath, serverlessVercelPackageJson);\n    const vcConfigFilePath = resolve(join(funcFolder, \".vc-config.json\"));\n    postBuildLogs.push(\n      `[one.build][vercel.createSsrServerlessFunction] writing .vc-config.json to ${vcConfigFilePath}`\n    );\n    return fs.writeJson(vcConfigFilePath, {\n      ...serverlessVercelNodeJsConfig,\n      handler: \"entrypoint/index.js\",\n      environment: {\n        ...serverlessVercelNodeJsConfig.environment,\n        ONE_DEFAULT_RENDER_MODE: \"ssr\"\n      }\n    });\n  } catch (e) {\n    console.error(\n      `[one.build][vercel.createSsrServerlessFunction] failed to generate func for ${route.file}`,\n      e\n    );\n  }\n}\nexport {\n  createSsrServerlessFunction\n};\n//# sourceMappingURL=createSsrServerlessFunction.js.map\n"],"mappings":";;;;;;;AAKA,eAAe,4BAA4B,OAAO,WAAW,gBAAgB,eAAe;CAC1F,IAAI;EACF,MAAM,OAAO,iBAAiB,OAAO,EAAE,cAAc,KAAK,CAAC;EAC3D,cAAc,KAAK,yDAAyD,MAAM;EAClF,MAAM,oBAAoB,KAAK,UAAU,SAAS;EAClD,MAAM,aAAa,QACjB,KAAK,gBAAgB,4BAA4B,KAAK,MAAM,CAC9D;EACA,MAAM,GAAG,UAAU,UAAU;EAC7B,MAAM,SAAS,UAAU,UAAU;EACnC,MAAM,iBAAiB,QAAQ,KAAK,gBAAgB,QAAQ,QAAQ,CAAC;EACrE,MAAM,eAAe,QAAQ,KAAK,YAAY,QAAQ,CAAC;EACvD,MAAM,GAAG,UAAU,YAAY;EAC/B,cAAc,KACZ,+EAA+E,eAAe,MAAM,cACtG;EACA,MAAM,GAAG,KAAK,gBAAgB,YAAY;EAC1C,cAAc,KACZ,wEACF;EACA,MAAM,GAAG,UACP,KAAK,YAAY,cAAc,GAC/B,kBAAkB,mBACpB;EACA,MAAM,GAAG,UAAU,KAAK,YAAY,YAAY,CAAC;EACjD,MAAM,qBAAqB,QAAQ,KAAK,YAAY,cAAc,UAAU,CAAC;EAC7E,cAAc,KACZ,yEAAyE,oBAC3E;EACA,MAAM,GAAG,UACP,oBACA;;;sBAGgB,KAAK,UAAU,MAAM,IAAI,EAAE;;;;;;;;;;2BAUtB,KAAK,UAAU,MAAM,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gEAsEU,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCnE;EACA,MAAM,sBAAsB,QAAQ,KAAK,YAAY,cAAc,CAAC;EACpE,cAAc,KACZ,2EAA2E,qBAC7E;EACA,MAAM,GAAG,UAAU,qBAAqB,2BAA2B;EACnE,MAAM,mBAAmB,QAAQ,KAAK,YAAY,iBAAiB,CAAC;EACpE,cAAc,KACZ,8EAA8E,kBAChF;EACA,OAAO,GAAG,UAAU,kBAAkB;GACpC,GAAG;GACH,SAAS;GACT,aAAa;IACX,GAAG,6BAA6B;IAChC,yBAAyB;GAC3B;EACF,CAAC;CACH,SAAS,GAAG;EACV,QAAQ,MACN,+EAA+E,MAAM,QACrF,CACF;CACF;AACF"}