{"version":3,"file":"node.cjs","names":[],"sources":["../../../src/adapters/node.ts"],"sourcesContent":["import { mkdir, rm, stat, writeFile } from \"node:fs/promises\";\nimport { relative, resolve } from \"node:path\";\nimport { build } from \"vite\";\nimport { scanRoutes } from \"../router/route-scanner.js\";\nimport type { Adapter } from \"./index.js\";\nimport { writeSsrEntry } from \"./shared.js\";\nimport { DEFAULT_CAPABILITIES } from \"../runtime/capabilities.js\";\n\n/**\n * Node adapter for nix-js-kit.\n *\n * Produces a self-contained Node server entry at `.nix-js/node-server.mjs`.\n * Run it with:\n *\n *   node .nix-js/node-server.mjs\n *\n * The server serves static files from `dist/` and renders pages on demand for\n * unmatched routes.\n */\nexport const nodeAdapter: Adapter = {\n  name: \"node\",\n  capabilities: DEFAULT_CAPABILITIES,\n\n  async build(options) {\n    const root = resolve(options.root);\n    const outDir = resolve(root, options.outDir);\n    const generatedDir = resolve(root, \".nix-js\");\n\n    try {\n      await stat(outDir);\n    } catch {\n      throw new Error(\n        `Output directory not found: ${outDir}. Run \"nix-js-kit build\" first.`,\n      );\n    }\n\n    await rm(generatedDir, { recursive: true, force: true });\n    await mkdir(generatedDir, { recursive: true });\n\n    const appDir = resolve(root, options.appDir);\n    const routes = await scanRoutes(appDir);\n\n    const entryPath = resolve(generatedDir, \"node-index.ts\");\n    await writeSsrEntry(entryPath, routes, options);\n\n    const serverPath = resolve(generatedDir, \"node-server.ts\");\n    await writeFile(\n      serverPath,\n      buildNodeServerSource(relativeToUrlPath(generatedDir, outDir), options),\n      \"utf8\",\n    );\n\n    await build({\n      configFile: false,\n      root,\n      build: {\n        outDir: generatedDir,\n        emptyOutDir: false,\n        ssr: true,\n        lib: {\n          entry: serverPath,\n          formats: [\"es\"],\n        },\n        rollupOptions: {\n          external: [/^@deijose\\/nix-js-kit(?:\\/.*)?$/, /^@deijose\\/nix-js(?:\\/.*)?$/, /^node:/],\n          output: {\n            entryFileNames: \"node-server.mjs\",\n            inlineDynamicImports: true,\n          },\n        },\n      },\n    });\n  },\n};\n\nfunction buildNodeServerSource(\n  outDirUrl: string,\n  options: {\n    clientEntry: string;\n    lang: string;\n    port?: number;\n  },\n): string {\n  return `// AUTO-GENERATED by @deijose/nix-js-kit. Do not edit.\nimport { createServer } from \"node:http\";\nimport { fileURLToPath } from \"node:url\";\nimport { createWebHandler } from \"@deijose/nix-js-kit/runtime\";\nimport { incomingMessageToRequest } from \"@deijose/nix-js-kit/runtime\";\nimport handler from \"./node-index.ts\";\n\nconst outDir = fileURLToPath(new URL(${JSON.stringify(outDirUrl)}, import.meta.url));\nconst port = Number(process.env.PORT) || ${options.port ?? 3000};\n\n// The adapter-bundled handler already handles actions, API routes, render\n// endpoint and dynamic SSR. We only need to add static file serving from\n// the output directory, then fall through to the bundled handler.\nconst webHandler = createWebHandler(\n  { pages: [], api: [], error404: undefined, error500: undefined },\n  {},\n  { staticRoot: outDir, lang: ${JSON.stringify(options.lang)}, clientEntry: ${JSON.stringify(options.clientEntry)} },\n);\n\ncreateServer(async (req, res) => {\n  const body = req.method !== \"GET\" && req.method !== \"HEAD\"\n    ? await readBody(req)\n    : undefined;\n  const request = incomingMessageToRequest(req, body);\n  // Try static files first via the unified handler, then fall back to the\n  // bundled SSR handler for dynamic routes.\n  let response = await webHandler(request);\n  if (response.status === 404) {\n    response = await handler(request);\n  }\n  res.writeHead(response.status, Object.fromEntries(response.headers.entries()));\n  res.end(Buffer.from(await response.arrayBuffer()));\n}).listen(port, () => {\n  console.log(\\`Node server running at http://localhost:\\${port}\\`);\n});\n\nfunction readBody(req: import(\"node:http\").IncomingMessage): Promise<Buffer> {\n  return new Promise((resolve, reject) => {\n    const chunks: Buffer[] = [];\n    req.on(\"data\", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));\n    req.on(\"end\", () => resolve(Buffer.concat(chunks)));\n    req.on(\"error\", reject);\n  });\n}\n`;\n}\n\nfunction relativeToUrlPath(from: string, to: string): string {\n  const path = relative(from, to).split(\"\\\\\").join(\"/\");\n  return `${path.startsWith(\".\") ? path : `./${path}`}/`;\n}\n"],"mappings":"6QAmBA,IAAa,EAAuB,CAClC,KAAM,OACN,aAAc,EAAA,EAEd,MAAM,MAAM,EAAS,CACnB,IAAM,GAAA,EAAO,EAAA,QAAA,CAAQ,EAAQ,IAAI,EAC3B,GAAA,EAAS,EAAA,QAAA,CAAQ,EAAM,EAAQ,MAAM,EACrC,GAAA,EAAe,EAAA,QAAA,CAAQ,EAAM,SAAS,EAE5C,GAAI,CACF,MAAA,EAAM,EAAA,KAAA,CAAK,CAAM,CACnB,MAAQ,CACN,MAAU,MACR,+BAA+B,EAAO,gCACxC,CACF,CAEA,MAAA,EAAM,EAAA,GAAA,CAAG,EAAc,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EACvD,MAAA,EAAM,EAAA,MAAA,CAAM,EAAc,CAAE,UAAW,EAAK,CAAC,EAE7C,IAAM,GAAA,EAAS,EAAA,QAAA,CAAQ,EAAM,EAAQ,MAAM,EACrC,EAAS,MAAM,EAAA,EAAW,CAAM,EAEhC,GAAA,EAAY,EAAA,QAAA,CAAQ,EAAc,eAAe,EACvD,MAAM,EAAA,EAAc,EAAW,EAAQ,CAAO,EAE9C,IAAM,GAAA,EAAa,EAAA,QAAA,CAAQ,EAAc,gBAAgB,EACzD,MAAA,EAAM,EAAA,UAAA,CACJ,EACA,EAAsB,EAAkB,EAAc,CAAM,EAAG,CAAO,EACtE,MACF,EAEA,MAAA,EAAM,EAAA,MAAA,CAAM,CACV,WAAY,GACZ,OACA,MAAO,CACL,OAAQ,EACR,YAAa,GACb,IAAK,GACL,IAAK,CACH,MAAO,EACP,QAAS,CAAC,IAAI,CAChB,EACA,cAAe,CACb,SAAU,CAAC,kCAAmC,8BAA+B,QAAQ,EACrF,OAAQ,CACN,eAAgB,kBAChB,qBAAsB,EACxB,CACF,CACF,CACF,CAAC,CACH,CACF,EAEA,SAAS,EACP,EACA,EAKQ,CACR,MAAO;;;;;;;uCAO8B,KAAK,UAAU,CAAS,EAAE;2CACtB,EAAQ,MAAQ,IAAK;;;;;;;;gCAQhC,KAAK,UAAU,EAAQ,IAAI,EAAE,iBAAiB,KAAK,UAAU,EAAQ,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BlH,CAEA,SAAS,EAAkB,EAAc,EAAoB,CAC3D,IAAM,GAAA,EAAO,EAAA,SAAA,CAAS,EAAM,CAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,GAAG,EACpD,MAAO,GAAG,EAAK,WAAW,GAAG,EAAI,EAAO,KAAK,IAAO,EACtD"}