@elurjs/kit 2.4.10 → 2.5.1

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.
Files changed (188) hide show
  1. package/CHANGELOG.md +313 -0
  2. package/README.md +248 -15
  3. package/dist/lib/action/index.cjs +1 -1
  4. package/dist/lib/action/index.js +1 -1
  5. package/dist/lib/{action-DZHihU3Z.cjs → action-BiE4tEty.cjs} +2 -2
  6. package/dist/lib/{action-DZHihU3Z.cjs.map → action-BiE4tEty.cjs.map} +1 -1
  7. package/dist/lib/{action-BB6N5yD-.js → action-CXVk8rWt.js} +3 -3
  8. package/dist/lib/{action-BB6N5yD-.js.map → action-CXVk8rWt.js.map} +1 -1
  9. package/dist/lib/adapter-DNsjXvq5.js +160 -0
  10. package/dist/lib/adapter-DNsjXvq5.js.map +1 -0
  11. package/dist/lib/adapter-Dz2hzR36.cjs +3 -0
  12. package/dist/lib/adapter-Dz2hzR36.cjs.map +1 -0
  13. package/dist/lib/adapters/bun.cjs +2 -2
  14. package/dist/lib/adapters/bun.cjs.map +1 -1
  15. package/dist/lib/adapters/bun.js +17 -9
  16. package/dist/lib/adapters/bun.js.map +1 -1
  17. package/dist/lib/adapters/index.d.cts +34 -0
  18. package/dist/lib/adapters/index.d.ts +34 -0
  19. package/dist/lib/adapters/netlify.cjs +1 -1
  20. package/dist/lib/adapters/netlify.js +7 -7
  21. package/dist/lib/adapters/node.cjs +5 -5
  22. package/dist/lib/adapters/node.cjs.map +1 -1
  23. package/dist/lib/adapters/node.js +20 -12
  24. package/dist/lib/adapters/node.js.map +1 -1
  25. package/dist/lib/adapters/vercel.cjs +1 -1
  26. package/dist/lib/adapters/vercel.js +8 -8
  27. package/dist/lib/build/build.d.cts +40 -0
  28. package/dist/lib/build/build.d.ts +40 -0
  29. package/dist/lib/build/document-shell.d.cts +47 -1
  30. package/dist/lib/build/document-shell.d.ts +47 -1
  31. package/dist/lib/build/vite-build.d.cts +25 -2
  32. package/dist/lib/build/vite-build.d.ts +25 -2
  33. package/dist/lib/cache/adapter.d.cts +41 -0
  34. package/dist/lib/cache/adapter.d.ts +41 -0
  35. package/dist/lib/cache/index.cjs +2 -0
  36. package/dist/lib/cache/index.cjs.map +1 -0
  37. package/dist/lib/cache/index.d.cts +5 -0
  38. package/dist/lib/cache/index.d.ts +5 -0
  39. package/dist/lib/cache/index.js +113 -0
  40. package/dist/lib/cache/index.js.map +1 -0
  41. package/dist/lib/cache/invalidation.d.cts +36 -0
  42. package/dist/lib/cache/invalidation.d.ts +36 -0
  43. package/dist/lib/cache/redis-adapter.d.cts +49 -0
  44. package/dist/lib/cache/redis-adapter.d.ts +49 -0
  45. package/dist/lib/cache-DGhTYyqh.js +50 -0
  46. package/dist/lib/cache-DGhTYyqh.js.map +1 -0
  47. package/dist/lib/cache-X1n4Ossu.cjs +2 -0
  48. package/dist/lib/cache-X1n4Ossu.cjs.map +1 -0
  49. package/dist/lib/cli/output.d.cts +58 -0
  50. package/dist/lib/cli/output.d.ts +58 -0
  51. package/dist/lib/cli/ports.d.cts +20 -0
  52. package/dist/lib/cli/ports.d.ts +20 -0
  53. package/dist/lib/cli.cjs +2559 -1488
  54. package/dist/lib/cli.cjs.map +1 -1
  55. package/dist/lib/cli.d.cts +21 -0
  56. package/dist/lib/cli.d.ts +21 -0
  57. package/dist/lib/cli.js +2558 -1488
  58. package/dist/lib/cli.js.map +1 -1
  59. package/dist/lib/config/index.cjs +1 -1
  60. package/dist/lib/config/index.cjs.map +1 -1
  61. package/dist/lib/config/index.d.cts +79 -0
  62. package/dist/lib/config/index.d.ts +79 -0
  63. package/dist/lib/config/index.js +21 -14
  64. package/dist/lib/config/index.js.map +1 -1
  65. package/dist/lib/{errors-ePYxDlhU.js → errors-j4cg9VN3.js} +24 -30
  66. package/dist/lib/{errors-ePYxDlhU.js.map → errors-j4cg9VN3.js.map} +1 -1
  67. package/dist/lib/errors-kSl9yLkg.cjs +2 -0
  68. package/dist/lib/{errors-0X7pCFNU.cjs.map → errors-kSl9yLkg.cjs.map} +1 -1
  69. package/dist/lib/hydrate-BSLuI0Nh.cjs +2 -0
  70. package/dist/lib/hydrate-BSLuI0Nh.cjs.map +1 -0
  71. package/dist/lib/hydrate-BaS7-d8C.js +133 -0
  72. package/dist/lib/hydrate-BaS7-d8C.js.map +1 -0
  73. package/dist/lib/idiomorph.esm-BOOTOg1r.cjs +2 -0
  74. package/dist/lib/idiomorph.esm-BOOTOg1r.cjs.map +1 -0
  75. package/dist/lib/idiomorph.esm-CXuY-EHB.js +371 -0
  76. package/dist/lib/idiomorph.esm-CXuY-EHB.js.map +1 -0
  77. package/dist/lib/index.cjs +1 -1
  78. package/dist/lib/index.cjs.map +1 -1
  79. package/dist/lib/index.d.cts +8 -6
  80. package/dist/lib/index.d.ts +8 -6
  81. package/dist/lib/index.js +1 -1
  82. package/dist/lib/index.js.map +1 -1
  83. package/dist/lib/interpolation-plugin-C0dTd69H.cjs +58 -0
  84. package/dist/lib/interpolation-plugin-C0dTd69H.cjs.map +1 -0
  85. package/dist/lib/{interpolation-plugin-Wgb1j4pT.js → interpolation-plugin-K2qE69tF.js} +95 -126
  86. package/dist/lib/interpolation-plugin-K2qE69tF.js.map +1 -0
  87. package/dist/lib/invalidation-CFpNQUv6.cjs +2 -0
  88. package/dist/lib/invalidation-CFpNQUv6.cjs.map +1 -0
  89. package/dist/lib/invalidation-DXhdE9wj.js +64 -0
  90. package/dist/lib/invalidation-DXhdE9wj.js.map +1 -0
  91. package/dist/lib/island/generate-entry.d.cts +40 -2
  92. package/dist/lib/island/generate-entry.d.ts +40 -2
  93. package/dist/lib/island/hydrate.d.cts +19 -6
  94. package/dist/lib/island/hydrate.d.ts +19 -6
  95. package/dist/lib/island/index.cjs +1 -1
  96. package/dist/lib/island/index.d.cts +2 -1
  97. package/dist/lib/island/index.d.ts +2 -1
  98. package/dist/lib/island/index.js +1 -1
  99. package/dist/lib/island/island.d.cts +15 -0
  100. package/dist/lib/island/island.d.ts +15 -0
  101. package/dist/lib/island-CTBnsOhI.js +59 -0
  102. package/dist/lib/island-CTBnsOhI.js.map +1 -0
  103. package/dist/lib/island-kfQEKRe_.cjs +2 -0
  104. package/dist/lib/island-kfQEKRe_.cjs.map +1 -0
  105. package/dist/lib/node-http-DVFcYeBS.js +723 -0
  106. package/dist/lib/node-http-DVFcYeBS.js.map +1 -0
  107. package/dist/lib/node-http-Uct7DhmN.cjs +13 -0
  108. package/dist/lib/node-http-Uct7DhmN.cjs.map +1 -0
  109. package/dist/lib/rolldown-runtime-BIInC43l.cjs +1 -0
  110. package/dist/lib/rolldown-runtime-Dy4uBu1J.js +11 -0
  111. package/dist/lib/router/client.cjs +1 -1
  112. package/dist/lib/router/client.cjs.map +1 -1
  113. package/dist/lib/router/client.d.cts +55 -8
  114. package/dist/lib/router/client.d.ts +55 -8
  115. package/dist/lib/router/client.js +298 -97
  116. package/dist/lib/router/client.js.map +1 -1
  117. package/dist/lib/router/redirects.d.cts +34 -0
  118. package/dist/lib/router/redirects.d.ts +34 -0
  119. package/dist/lib/runtime/handler.d.cts +59 -0
  120. package/dist/lib/runtime/handler.d.ts +59 -0
  121. package/dist/lib/runtime/index.cjs +1 -1
  122. package/dist/lib/runtime/index.d.cts +2 -1
  123. package/dist/lib/runtime/index.d.ts +2 -1
  124. package/dist/lib/runtime/index.js +4 -4
  125. package/dist/lib/runtime/logger.d.cts +47 -0
  126. package/dist/lib/runtime/logger.d.ts +47 -0
  127. package/dist/lib/runtime/node-http.d.cts +11 -1
  128. package/dist/lib/runtime/node-http.d.ts +11 -1
  129. package/dist/lib/runtime-ChE4flX3.cjs +2 -0
  130. package/dist/lib/runtime-ChE4flX3.cjs.map +1 -0
  131. package/dist/lib/runtime-OMyz5yE-.js +905 -0
  132. package/dist/lib/runtime-OMyz5yE-.js.map +1 -0
  133. package/dist/lib/seo/index.cjs +1 -10
  134. package/dist/lib/seo/index.d.cts +1 -0
  135. package/dist/lib/seo/index.d.ts +1 -0
  136. package/dist/lib/seo/index.js +2 -41
  137. package/dist/lib/seo/sitemap-from-routes.d.cts +24 -0
  138. package/dist/lib/seo/sitemap-from-routes.d.ts +24 -0
  139. package/dist/lib/{shared-CfqOLsKj.cjs → shared-CP0Dc3cp.cjs} +72 -47
  140. package/dist/lib/shared-CP0Dc3cp.cjs.map +1 -0
  141. package/dist/lib/{shared-DU3iQgr7.js → shared-D8w-neq2.js} +87 -58
  142. package/dist/lib/shared-D8w-neq2.js.map +1 -0
  143. package/dist/lib/sitemap-from-routes-CaBoiGvE.js +77 -0
  144. package/dist/lib/sitemap-from-routes-CaBoiGvE.js.map +1 -0
  145. package/dist/lib/sitemap-from-routes-DbcLLL4G.cjs +13 -0
  146. package/dist/lib/sitemap-from-routes-DbcLLL4G.cjs.map +1 -0
  147. package/dist/lib/ssr/render.d.cts +8 -2
  148. package/dist/lib/ssr/render.d.ts +8 -2
  149. package/dist/lib/ssr/server.d.cts +7 -0
  150. package/dist/lib/ssr/server.d.ts +7 -0
  151. package/dist/lib/ssr/stream-response.d.cts +30 -0
  152. package/dist/lib/ssr/stream-response.d.ts +30 -0
  153. package/dist/lib/ssr/stream.d.cts +16 -1
  154. package/dist/lib/ssr/stream.d.ts +16 -1
  155. package/dist/lib/{stream-DmZjYqHm.cjs → stream-Cg-xYG82.cjs} +3 -3
  156. package/dist/lib/stream-Cg-xYG82.cjs.map +1 -0
  157. package/dist/lib/stream-D-ytogdu.js +106 -0
  158. package/dist/lib/stream-D-ytogdu.js.map +1 -0
  159. package/dist/lib/vite/index.cjs +1 -1
  160. package/dist/lib/vite/index.cjs.map +1 -1
  161. package/dist/lib/vite/index.d.cts +11 -0
  162. package/dist/lib/vite/index.d.ts +11 -0
  163. package/dist/lib/vite/index.js +101 -94
  164. package/dist/lib/vite/index.js.map +1 -1
  165. package/package.json +25 -8
  166. package/dist/lib/errors-0X7pCFNU.cjs +0 -2
  167. package/dist/lib/hydrate-CJbUWdXu.js +0 -126
  168. package/dist/lib/hydrate-CJbUWdXu.js.map +0 -1
  169. package/dist/lib/hydrate-D6MR24mz.cjs +0 -2
  170. package/dist/lib/hydrate-D6MR24mz.cjs.map +0 -1
  171. package/dist/lib/interpolation-plugin-TWDch8nn.cjs +0 -39
  172. package/dist/lib/interpolation-plugin-TWDch8nn.cjs.map +0 -1
  173. package/dist/lib/interpolation-plugin-Wgb1j4pT.js.map +0 -1
  174. package/dist/lib/node-http-DRAUhO0c.js +0 -617
  175. package/dist/lib/node-http-DRAUhO0c.js.map +0 -1
  176. package/dist/lib/node-http-DhxguYyz.cjs +0 -13
  177. package/dist/lib/node-http-DhxguYyz.cjs.map +0 -1
  178. package/dist/lib/runtime-CrH5X-Es.cjs +0 -2
  179. package/dist/lib/runtime-CrH5X-Es.cjs.map +0 -1
  180. package/dist/lib/runtime-Ds2-wH6P.js +0 -520
  181. package/dist/lib/runtime-Ds2-wH6P.js.map +0 -1
  182. package/dist/lib/seo/index.cjs.map +0 -1
  183. package/dist/lib/seo/index.js.map +0 -1
  184. package/dist/lib/shared-CfqOLsKj.cjs.map +0 -1
  185. package/dist/lib/shared-DU3iQgr7.js.map +0 -1
  186. package/dist/lib/stream-CpOG052V.js +0 -104
  187. package/dist/lib/stream-CpOG052V.js.map +0 -1
  188. package/dist/lib/stream-DmZjYqHm.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"node.js","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 elur-kit.\n *\n * Produces a self-contained Node server entry at `.elur/node-server.mjs`.\n * Run it with:\n *\n * node .elur/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, \".elur\");\n\n try {\n await stat(outDir);\n } catch {\n throw new Error(\n `Output directory not found: ${outDir}. Run \"elur-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: [/^@elurjs\\/kit(?:\\/.*)?$/, /^@elurjs\\/core(?:\\/.*)?$/, /^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 @elurjs/kit. Do not edit.\nimport { createServer } from \"node:http\";\nimport { fileURLToPath } from \"node:url\";\nimport { createWebHandler } from \"@elurjs/kit/runtime\";\nimport { incomingMessageToRequest } from \"@elurjs/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":";;;;;;;AAmBA,IAAa,IAAuB;CAClC,MAAM;CACN,cAAc;CAEd,MAAM,MAAM,GAAS;EACnB,IAAM,IAAO,EAAQ,EAAQ,IAAI,GAC3B,IAAS,EAAQ,GAAM,EAAQ,MAAM,GACrC,IAAe,EAAQ,GAAM,OAAO;EAE1C,IAAI;GACF,MAAM,EAAK,CAAM;EACnB,QAAQ;GACN,MAAU,MACR,+BAA+B,EAAO,8BACxC;EACF;EAGA,AADA,MAAM,EAAG,GAAc;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC,GACvD,MAAM,EAAM,GAAc,EAAE,WAAW,GAAK,CAAC;EAE7C,IAAM,IAAS,EAAQ,GAAM,EAAQ,MAAM,GACrC,IAAS,MAAM,EAAW,CAAM,GAEhC,IAAY,EAAQ,GAAc,eAAe;EACvD,MAAM,EAAc,GAAW,GAAQ,CAAO;EAE9C,IAAM,IAAa,EAAQ,GAAc,gBAAgB;EAOzD,AANA,MAAM,EACJ,GACA,EAAsB,EAAkB,GAAc,CAAM,GAAG,CAAO,GACtE,MACF,GAEA,MAAM,EAAM;GACV,YAAY;GACZ;GACA,OAAO;IACL,QAAQ;IACR,aAAa;IACb,KAAK;IACL,KAAK;KACH,OAAO;KACP,SAAS,CAAC,IAAI;IAChB;IACA,eAAe;KACb,UAAU;MAAC;MAA2B;MAA4B;KAAQ;KAC1E,QAAQ;MACN,gBAAgB;MAChB,sBAAsB;KACxB;IACF;GACF;EACF,CAAC;CACH;AACF;AAEA,SAAS,EACP,GACA,GAKQ;CACR,OAAO;;;;;;;uCAO8B,KAAK,UAAU,CAAS,EAAE;2CACtB,EAAQ,QAAQ,IAAK;;;;;;;;gCAQhC,KAAK,UAAU,EAAQ,IAAI,EAAE,iBAAiB,KAAK,UAAU,EAAQ,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BlH;AAEA,SAAS,EAAkB,GAAc,GAAoB;CAC3D,IAAM,IAAO,EAAS,GAAM,CAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,GAAG;CACpD,OAAO,GAAG,EAAK,WAAW,GAAG,IAAI,IAAO,KAAK,IAAO;AACtD"}
1
+ {"version":3,"file":"node.js","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 elur-kit.\n *\n * Produces a self-contained Node server entry at `.elur/node-server.mjs`.\n * Run it with:\n *\n * node .elur/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, \".elur\");\n\n try {\n await stat(outDir);\n } catch {\n throw new Error(\n `Output directory not found: ${outDir}. Run \"elur-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: [/^@elurjs\\/kit(?:\\/.*)?$/, /^@elurjs\\/core(?:\\/.*)?$/, /^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 logLevel?: string;\n redirects?: import(\"../router/redirects.js\").RedirectRule[];\n rewrites?: import(\"../router/redirects.js\").RewriteRule[];\n routeHeaders?: import(\"../router/redirects.js\").RouteHeadersRule[];\n },\n): string {\n const logLevelOption = options.logLevel ? `, logLevel: ${JSON.stringify(options.logLevel)}` : \"\";\n // Rule arrays are plain data: emit them as JSON literals when defined.\n const routingOptions = ([\"redirects\", \"rewrites\", \"routeHeaders\"] as const)\n .map((key) => {\n const rules = options[key];\n return rules && rules.length > 0 ? `, ${key}: ${JSON.stringify(rules)}` : \"\";\n })\n .join(\"\");\n return `// AUTO-GENERATED by @elurjs/kit. Do not edit.\nimport { createServer } from \"node:http\";\nimport { fileURLToPath } from \"node:url\";\nimport { createWebHandler } from \"@elurjs/kit/runtime\";\nimport { incomingMessageToRequest, sendWebResponse } from \"@elurjs/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)}${logLevelOption}${routingOptions} },\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 // Streams the body: streaming SSR chunks flush as they are produced.\n await sendWebResponse(res, response);\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":";;;;;;;AAmBA,IAAa,IAAuB;CAClC,MAAM;CACN,cAAc;CAEd,MAAM,MAAM,GAAS;EACnB,IAAM,IAAO,EAAQ,EAAQ,IAAI,GAC3B,IAAS,EAAQ,GAAM,EAAQ,MAAM,GACrC,IAAe,EAAQ,GAAM,OAAO;EAE1C,IAAI;GACF,MAAM,EAAK,CAAM;EACnB,QAAQ;GACN,MAAU,MACR,+BAA+B,EAAO,8BACxC;EACF;EAGA,AADA,MAAM,EAAG,GAAc;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC,GACvD,MAAM,EAAM,GAAc,EAAE,WAAW,GAAK,CAAC;EAE7C,IAAM,IAAS,EAAQ,GAAM,EAAQ,MAAM,GACrC,IAAS,MAAM,EAAW,CAAM,GAEhC,IAAY,EAAQ,GAAc,eAAe;EACvD,MAAM,EAAc,GAAW,GAAQ,CAAO;EAE9C,IAAM,IAAa,EAAQ,GAAc,gBAAgB;EAOzD,AANA,MAAM,EACJ,GACA,EAAsB,EAAkB,GAAc,CAAM,GAAG,CAAO,GACtE,MACF,GAEA,MAAM,EAAM;GACV,YAAY;GACZ;GACA,OAAO;IACL,QAAQ;IACR,aAAa;IACb,KAAK;IACL,KAAK;KACH,OAAO;KACP,SAAS,CAAC,IAAI;IAChB;IACA,eAAe;KACb,UAAU;MAAC;MAA2B;MAA4B;KAAQ;KAC1E,QAAQ;MACN,gBAAgB;MAChB,sBAAsB;KACxB;IACF;GACF;EACF,CAAC;CACH;AACF;AAEA,SAAS,EACP,GACA,GASQ;CACR,IAAM,IAAiB,EAAQ,WAAW,eAAe,KAAK,UAAU,EAAQ,QAAQ,MAAM,IAExF,IAAkB;EAAC;EAAa;EAAY;CAAc,CAAC,CAC9D,KAAK,MAAQ;EACZ,IAAM,IAAQ,EAAQ;EACtB,OAAO,KAAS,EAAM,SAAS,IAAI,KAAK,EAAI,IAAI,KAAK,UAAU,CAAK,MAAM;CAC5E,CAAC,CAAC,CACD,KAAK,EAAE;CACV,OAAO;;;;;;;uCAO8B,KAAK,UAAU,CAAS,EAAE;2CACtB,EAAQ,QAAQ,IAAK;;;;;;;;gCAQhC,KAAK,UAAU,EAAQ,IAAI,EAAE,iBAAiB,KAAK,UAAU,EAAQ,WAAW,IAAI,IAAiB,EAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BpJ;AAEA,SAAS,EAAkB,GAAc,GAAoB;CAC3D,IAAM,IAAO,EAAS,GAAM,CAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,GAAG;CACpD,OAAO,GAAG,EAAK,WAAW,GAAG,IAAI,IAAO,KAAK,IAAO;AACtD"}
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../route-scanner-JY6YrNH5.cjs"),t=require("../shared-CfqOLsKj.cjs"),n=require("../capabilities-C0TDQoMY.cjs");let r=require("node:fs/promises"),i=require("node:path"),a=require("vite");var o={name:`vercel`,capabilities:n.r,async build(n){let o=(0,i.resolve)(n.root),s=(0,i.resolve)(o,n.outDir),c=(0,i.resolve)(o,`.vercel/output`),l=(0,i.join)(c,`functions`,`__elur-js-kit.func`),u=(0,i.resolve)(o,`.elur`);try{await(0,r.stat)(s)}catch{throw Error(`Output directory not found: ${s}. Run "elur-kit build" first.`)}await(0,r.rm)(c,{recursive:!0,force:!0}),await(0,r.mkdir)(c,{recursive:!0}),await(0,r.mkdir)(l,{recursive:!0}),await(0,r.mkdir)(u,{recursive:!0}),await t.t(s,(0,i.join)(c,`static`));let d=(0,i.resolve)(o,n.appDir),f=await e.t(d),p=(0,i.resolve)(u,`vercel-index.ts`);await t.n(p,f,n),await(0,a.build)({configFile:!1,root:o,build:{outDir:l,emptyOutDir:!0,ssr:!0,lib:{entry:p,formats:[`es`],fileName:()=>`index.js`},rollupOptions:{external:[],output:{inlineDynamicImports:!0}}}});let m=(0,i.join)(l,`vercel-index.js`),h=(0,i.join)(l,`index.js`);try{await(0,r.stat)(m),await(0,r.rename)(m,h)}catch{}await(0,r.writeFile)((0,i.join)(l,`.vc-config.json`),JSON.stringify({runtime:`nodejs20.x`,handler:`index.js`,launcherType:`Nodejs`,shouldAddHelpers:!0},null,2),`utf8`),await(0,r.writeFile)((0,i.join)(c,`config.json`),JSON.stringify({version:3,routes:[{handle:`filesystem`},{src:`/(.*)`,dest:`/__elur-js-kit`}]},null,2),`utf8`)}};exports.vercelAdapter=o;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../route-scanner-JY6YrNH5.cjs"),t=require("../capabilities-C0TDQoMY.cjs"),n=require("../shared-CP0Dc3cp.cjs");let r=require("node:fs/promises"),i=require("node:path"),a=require("vite");var o={name:`vercel`,capabilities:t.r,async build(t){let o=(0,i.resolve)(t.root),s=(0,i.resolve)(o,t.outDir),c=(0,i.resolve)(o,`.vercel/output`),l=(0,i.join)(c,`functions`,`__elur-js-kit.func`),u=(0,i.resolve)(o,`.elur`);try{await(0,r.stat)(s)}catch{throw Error(`Output directory not found: ${s}. Run "elur-kit build" first.`)}await(0,r.rm)(c,{recursive:!0,force:!0}),await(0,r.mkdir)(c,{recursive:!0}),await(0,r.mkdir)(l,{recursive:!0}),await(0,r.mkdir)(u,{recursive:!0}),await n.t(s,(0,i.join)(c,`static`));let d=(0,i.resolve)(o,t.appDir),f=await e.t(d),p=(0,i.resolve)(u,`vercel-index.ts`);await n.n(p,f,t),await(0,a.build)({configFile:!1,root:o,build:{outDir:l,emptyOutDir:!0,ssr:!0,lib:{entry:p,formats:[`es`],fileName:()=>`index.js`},rollupOptions:{external:[],output:{inlineDynamicImports:!0}}}});let m=(0,i.join)(l,`vercel-index.js`),h=(0,i.join)(l,`index.js`);try{await(0,r.stat)(m),await(0,r.rename)(m,h)}catch{}await(0,r.writeFile)((0,i.join)(l,`.vc-config.json`),JSON.stringify({runtime:`nodejs20.x`,handler:`index.js`,launcherType:`Nodejs`,shouldAddHelpers:!0},null,2),`utf8`),await(0,r.writeFile)((0,i.join)(c,`config.json`),JSON.stringify({version:3,routes:[{handle:`filesystem`},{src:`/(.*)`,dest:`/__elur-js-kit`}]},null,2),`utf8`)}};exports.vercelAdapter=o;
2
2
  //# sourceMappingURL=vercel.cjs.map
@@ -1,15 +1,15 @@
1
1
  import { t as e } from "../route-scanner-XcLId7lK.js";
2
- import { n as t, t as n } from "../shared-DU3iQgr7.js";
3
- import { r } from "../capabilities-C7txofmY.js";
2
+ import { r as t } from "../capabilities-C7txofmY.js";
3
+ import { n, t as r } from "../shared-D8w-neq2.js";
4
4
  import { mkdir as i, rename as a, rm as o, stat as s, writeFile as c } from "node:fs/promises";
5
5
  import { join as l, resolve as u } from "node:path";
6
6
  import { build as d } from "vite";
7
7
  //#region src/adapters/vercel.ts
8
8
  var f = {
9
9
  name: "vercel",
10
- capabilities: r,
11
- async build(r) {
12
- let f = u(r.root), p = u(f, r.outDir), m = u(f, ".vercel/output"), h = l(m, "functions", "__elur-js-kit.func"), g = u(f, ".elur");
10
+ capabilities: t,
11
+ async build(t) {
12
+ let f = u(t.root), p = u(f, t.outDir), m = u(f, ".vercel/output"), h = l(m, "functions", "__elur-js-kit.func"), g = u(f, ".elur");
13
13
  try {
14
14
  await s(p);
15
15
  } catch {
@@ -18,9 +18,9 @@ var f = {
18
18
  await o(m, {
19
19
  recursive: !0,
20
20
  force: !0
21
- }), await i(m, { recursive: !0 }), await i(h, { recursive: !0 }), await i(g, { recursive: !0 }), await n(p, l(m, "static"));
22
- let _ = u(f, r.appDir), v = await e(_), y = u(g, "vercel-index.ts");
23
- await t(y, v, r), await d({
21
+ }), await i(m, { recursive: !0 }), await i(h, { recursive: !0 }), await i(g, { recursive: !0 }), await r(p, l(m, "static"));
22
+ let _ = u(f, t.appDir), v = await e(_), y = u(g, "vercel-index.ts");
23
+ await n(y, v, t), await d({
24
24
  configFile: !1,
25
25
  root: f,
26
26
  build: {
@@ -46,6 +46,38 @@ export interface BuildConfig {
46
46
  * the endpoint (no 404 storms on static hosts like Vercel).
47
47
  */
48
48
  renderEndpoint?: boolean;
49
+ /**
50
+ * Client router options (Fase 8.3 + §9). `enabled`/`prefetch`/`morph`/
51
+ * `loadingIndicator` are baked into the generated entry; `separate` makes
52
+ * the router its own generated module (emitted as its own chunk when the
53
+ * client bundle declares it as an input) so pages without islands only
54
+ * load `router.js`; `entry` is that chunk's public URL; `speculation`
55
+ * emits a Speculation Rules block on static pages.
56
+ */
57
+ router?: {
58
+ enabled?: boolean;
59
+ prefetch?: boolean;
60
+ morph?: boolean;
61
+ loadingIndicator?: boolean;
62
+ speculation?: "prefetch" | "prerender";
63
+ /** Generate a standalone router module next to the client entry. */
64
+ separate?: boolean;
65
+ /** Public URL of the router chunk (default: "/_elur/router.js"). */
66
+ entry?: string;
67
+ /** Path of the generated router module (default: sibling "router.ts"). */
68
+ outFile?: string;
69
+ };
70
+ /**
71
+ * Client JS emission mode: `"modern"` gates the entry per page (0% JS);
72
+ * `"legacy"` emits the combined entry unconditionally on every page.
73
+ */
74
+ js?: "modern" | "legacy";
75
+ /**
76
+ * Public site URL (e.g. "https://example.com"). When set, the build
77
+ * generates `sitemap.xml` from the scanned routes automatically, unless
78
+ * one already exists in the output (from `public/` or an integration).
79
+ */
80
+ site?: string;
49
81
  /**
50
82
  * Integrations to invoke during the build lifecycle. When provided, the
51
83
  * `build` hook fires after all pages and image variants are generated,
@@ -53,6 +85,14 @@ export interface BuildConfig {
53
85
  * robots.txt, search indexes, etc.) into the output directory.
54
86
  */
55
87
  integrations?: ElurKitIntegration[];
88
+ /**
89
+ * Optional observer invoked once per build phase with its duration in
90
+ * milliseconds ("scan", "pages", "images", "integrations", "sitemap").
91
+ * Phases that don't run (no images, no integrations, no site URL) are not
92
+ * reported. Used by the CLI to render progress; the build itself stays
93
+ * silent.
94
+ */
95
+ onPhase?: (name: string, durationMs: number) => void;
56
96
  }
57
97
  export interface BuildResult {
58
98
  /** Number of static HTML pages generated. */
@@ -46,6 +46,38 @@ export interface BuildConfig {
46
46
  * the endpoint (no 404 storms on static hosts like Vercel).
47
47
  */
48
48
  renderEndpoint?: boolean;
49
+ /**
50
+ * Client router options (Fase 8.3 + §9). `enabled`/`prefetch`/`morph`/
51
+ * `loadingIndicator` are baked into the generated entry; `separate` makes
52
+ * the router its own generated module (emitted as its own chunk when the
53
+ * client bundle declares it as an input) so pages without islands only
54
+ * load `router.js`; `entry` is that chunk's public URL; `speculation`
55
+ * emits a Speculation Rules block on static pages.
56
+ */
57
+ router?: {
58
+ enabled?: boolean;
59
+ prefetch?: boolean;
60
+ morph?: boolean;
61
+ loadingIndicator?: boolean;
62
+ speculation?: "prefetch" | "prerender";
63
+ /** Generate a standalone router module next to the client entry. */
64
+ separate?: boolean;
65
+ /** Public URL of the router chunk (default: "/_elur/router.js"). */
66
+ entry?: string;
67
+ /** Path of the generated router module (default: sibling "router.ts"). */
68
+ outFile?: string;
69
+ };
70
+ /**
71
+ * Client JS emission mode: `"modern"` gates the entry per page (0% JS);
72
+ * `"legacy"` emits the combined entry unconditionally on every page.
73
+ */
74
+ js?: "modern" | "legacy";
75
+ /**
76
+ * Public site URL (e.g. "https://example.com"). When set, the build
77
+ * generates `sitemap.xml` from the scanned routes automatically, unless
78
+ * one already exists in the output (from `public/` or an integration).
79
+ */
80
+ site?: string;
49
81
  /**
50
82
  * Integrations to invoke during the build lifecycle. When provided, the
51
83
  * `build` hook fires after all pages and image variants are generated,
@@ -53,6 +85,14 @@ export interface BuildConfig {
53
85
  * robots.txt, search indexes, etc.) into the output directory.
54
86
  */
55
87
  integrations?: ElurKitIntegration[];
88
+ /**
89
+ * Optional observer invoked once per build phase with its duration in
90
+ * milliseconds ("scan", "pages", "images", "integrations", "sitemap").
91
+ * Phases that don't run (no images, no integrations, no site URL) are not
92
+ * reported. Used by the CLI to render progress; the build itself stays
93
+ * silent.
94
+ */
95
+ onPhase?: (name: string, durationMs: number) => void;
56
96
  }
57
97
  export interface BuildResult {
58
98
  /** Number of static HTML pages generated. */
@@ -1,4 +1,5 @@
1
1
  import type { PageMetadata } from "../types.js";
2
+ export type SpeculationMode = "prefetch" | "prerender";
2
3
  export interface ShellOptions {
3
4
  /** Rendered inner HTML that goes inside `#app`. */
4
5
  body: string;
@@ -25,8 +26,33 @@ export interface ShellOptions {
25
26
  data?: unknown;
26
27
  /** Per-page action names serialized into `<script id="elur-actions">`. */
27
28
  actions?: Record<string, string[]>;
28
- /** Path to the client entry module, e.g. `/_elur/entry-client.js`. */
29
+ /**
30
+ * Path to the client entry module, e.g. `/_elur/entry-client.js`. In split
31
+ * builds this is the hydrate-only entry; callers gate it per page so it is
32
+ * only emitted when the rendered body actually contains islands.
33
+ */
29
34
  clientEntry?: string;
35
+ /**
36
+ * Path to the standalone client router module, e.g. `/_elur/router.js`
37
+ * (split builds only). Emitted as a second `<script type="module">` so pages
38
+ * without islands still get SPA navigation without paying for the islands
39
+ * entry.
40
+ */
41
+ routerEntry?: string;
42
+ /**
43
+ * Whether the client router is enabled for this page. When `false`, the
44
+ * `elur:render-endpoint` meta is omitted entirely: no client router will run,
45
+ * so there is nothing to advertise endpoint availability to.
46
+ */
47
+ routerEnabled?: boolean;
48
+ /**
49
+ * Speculation Rules API mode emitted as
50
+ * `<script type="speculationrules">` with document rules and
51
+ * `eagerness: "moderate"`. Chromium-only progressive enhancement — other
52
+ * browsers ignore the unknown script type. Only set this for static builds;
53
+ * never apply to URLs reachable via server actions.
54
+ */
55
+ speculation?: SpeculationMode;
30
56
  /** Page metadata emitted as `<meta>`, `<link>` and OG/Twitter tags in `<head>`. */
31
57
  metadata?: PageMetadata;
32
58
  /**
@@ -38,6 +64,26 @@ export interface ShellOptions {
38
64
  */
39
65
  renderEndpoint?: boolean;
40
66
  }
67
+ /**
68
+ * Explicit delimiters around the `#app` content. The streaming pipeline
69
+ * (`createStreamingResponse`) and adapter render endpoints extract the page
70
+ * body with these markers instead of parsing the shell layout by hand, so
71
+ * changes to the shell markup never break extraction. They are HTML comments:
72
+ * invisible, and ignored by hydration and the SPA router.
73
+ */
74
+ export declare const APP_START_MARKER = "<!--elur:app:start-->";
75
+ export declare const APP_END_MARKER = "<!--elur:app:end-->";
76
+ /**
77
+ * Extracts the inner HTML of `#app` from a full document produced by
78
+ * `documentShell`. Returns `undefined` when the markers are missing (e.g. a
79
+ * hand-written document).
80
+ */
81
+ export declare function extractAppBody(html: string): string | undefined;
82
+ /**
83
+ * Serializes data for embedding inside a `<script>` tag. Escapes `<` so a
84
+ * `</script>` sequence in the data cannot break out of the tag.
85
+ */
86
+ export declare function serializeData(data: unknown): string;
41
87
  /**
42
88
  * Builds the `<head>` tags for a `PageMetadata` object. Every tag is marked with
43
89
  * `data-elur-head` so the client-side router can replace them on navigation
@@ -1,4 +1,5 @@
1
1
  import type { PageMetadata } from "../types.js";
2
+ export type SpeculationMode = "prefetch" | "prerender";
2
3
  export interface ShellOptions {
3
4
  /** Rendered inner HTML that goes inside `#app`. */
4
5
  body: string;
@@ -25,8 +26,33 @@ export interface ShellOptions {
25
26
  data?: unknown;
26
27
  /** Per-page action names serialized into `<script id="elur-actions">`. */
27
28
  actions?: Record<string, string[]>;
28
- /** Path to the client entry module, e.g. `/_elur/entry-client.js`. */
29
+ /**
30
+ * Path to the client entry module, e.g. `/_elur/entry-client.js`. In split
31
+ * builds this is the hydrate-only entry; callers gate it per page so it is
32
+ * only emitted when the rendered body actually contains islands.
33
+ */
29
34
  clientEntry?: string;
35
+ /**
36
+ * Path to the standalone client router module, e.g. `/_elur/router.js`
37
+ * (split builds only). Emitted as a second `<script type="module">` so pages
38
+ * without islands still get SPA navigation without paying for the islands
39
+ * entry.
40
+ */
41
+ routerEntry?: string;
42
+ /**
43
+ * Whether the client router is enabled for this page. When `false`, the
44
+ * `elur:render-endpoint` meta is omitted entirely: no client router will run,
45
+ * so there is nothing to advertise endpoint availability to.
46
+ */
47
+ routerEnabled?: boolean;
48
+ /**
49
+ * Speculation Rules API mode emitted as
50
+ * `<script type="speculationrules">` with document rules and
51
+ * `eagerness: "moderate"`. Chromium-only progressive enhancement — other
52
+ * browsers ignore the unknown script type. Only set this for static builds;
53
+ * never apply to URLs reachable via server actions.
54
+ */
55
+ speculation?: SpeculationMode;
30
56
  /** Page metadata emitted as `<meta>`, `<link>` and OG/Twitter tags in `<head>`. */
31
57
  metadata?: PageMetadata;
32
58
  /**
@@ -38,6 +64,26 @@ export interface ShellOptions {
38
64
  */
39
65
  renderEndpoint?: boolean;
40
66
  }
67
+ /**
68
+ * Explicit delimiters around the `#app` content. The streaming pipeline
69
+ * (`createStreamingResponse`) and adapter render endpoints extract the page
70
+ * body with these markers instead of parsing the shell layout by hand, so
71
+ * changes to the shell markup never break extraction. They are HTML comments:
72
+ * invisible, and ignored by hydration and the SPA router.
73
+ */
74
+ export declare const APP_START_MARKER = "<!--elur:app:start-->";
75
+ export declare const APP_END_MARKER = "<!--elur:app:end-->";
76
+ /**
77
+ * Extracts the inner HTML of `#app` from a full document produced by
78
+ * `documentShell`. Returns `undefined` when the markers are missing (e.g. a
79
+ * hand-written document).
80
+ */
81
+ export declare function extractAppBody(html: string): string | undefined;
82
+ /**
83
+ * Serializes data for embedding inside a `<script>` tag. Escapes `<` so a
84
+ * `</script>` sequence in the data cannot break out of the tag.
85
+ */
86
+ export declare function serializeData(data: unknown): string;
41
87
  /**
42
88
  * Builds the `<head>` tags for a `PageMetadata` object. Every tag is marked with
43
89
  * `data-elur-head` so the client-side router can replace them on navigation
@@ -1,9 +1,22 @@
1
+ import { type InlineConfig } from "vite";
1
2
  import { type InterpolationMode } from "../vite/interpolation-plugin.js";
2
3
  export interface ClientBuildOptions {
3
4
  /** Project root (absolute). */
4
5
  root: string;
5
- /** Absolute path to the user's Vite client config (e.g. vite.client.config.ts). */
6
- userConfigPath: string;
6
+ /**
7
+ * Absolute path to the user's Vite client config (e.g.
8
+ * vite.client.config.ts). When omitted, a default config is generated
9
+ * from `defaultInputs` — the generated entry plus, in split builds, the
10
+ * generated router module — so projects get a working bundle with zero
11
+ * client config.
12
+ */
13
+ userConfigPath?: string;
14
+ /**
15
+ * Default bundle inputs (name → absolute entry path) used when no user
16
+ * config is present. With `entry-client` + `router` keys the output is
17
+ * `entry-client.js` + `router.js`.
18
+ */
19
+ defaultInputs?: Record<string, string>;
7
20
  /** Absolute path to the app directory (used by the interpolation plugin). */
8
21
  appDir: string;
9
22
  /** Absolute path to the islands directory (used by the interpolation plugin). */
@@ -14,6 +27,8 @@ export interface ClientBuildOptions {
14
27
  base?: string;
15
28
  /** Optional log prefix. */
16
29
  logPrefix?: string;
30
+ /** Suppress bundle logs (kit's and Vite's); errors still surface. */
31
+ quiet?: boolean;
17
32
  /**
18
33
  * How the legacy interpolation transform is handled (default: "auto").
19
34
  * With a Elur core that supports partial attribute interpolation natively
@@ -36,6 +51,14 @@ export interface ClientBuildResult {
36
51
  * transformed before reaching the browser.
37
52
  */
38
53
  export declare function buildClientBundle(options: ClientBuildOptions): Promise<ClientBuildResult>;
54
+ export declare function loadUserConfig(path: string, _root: string): Promise<InlineConfig>;
55
+ /**
56
+ * Resolves a user Vite config's `build.rollupOptions.input` to a list of
57
+ * absolute entry paths. Used to detect whether the bundle will emit the
58
+ * generated router module as its own chunk (split build) or not (legacy
59
+ * single-entry bundle — the router stays embedded in the entry).
60
+ */
61
+ export declare function resolveClientInputs(userConfigPath: string, root: string): Promise<string[]>;
39
62
  export interface AtomicStageOptions {
40
63
  /** Final destination directory (absolute). */
41
64
  outDir: string;
@@ -1,9 +1,22 @@
1
+ import { type InlineConfig } from "vite";
1
2
  import { type InterpolationMode } from "../vite/interpolation-plugin.js";
2
3
  export interface ClientBuildOptions {
3
4
  /** Project root (absolute). */
4
5
  root: string;
5
- /** Absolute path to the user's Vite client config (e.g. vite.client.config.ts). */
6
- userConfigPath: string;
6
+ /**
7
+ * Absolute path to the user's Vite client config (e.g.
8
+ * vite.client.config.ts). When omitted, a default config is generated
9
+ * from `defaultInputs` — the generated entry plus, in split builds, the
10
+ * generated router module — so projects get a working bundle with zero
11
+ * client config.
12
+ */
13
+ userConfigPath?: string;
14
+ /**
15
+ * Default bundle inputs (name → absolute entry path) used when no user
16
+ * config is present. With `entry-client` + `router` keys the output is
17
+ * `entry-client.js` + `router.js`.
18
+ */
19
+ defaultInputs?: Record<string, string>;
7
20
  /** Absolute path to the app directory (used by the interpolation plugin). */
8
21
  appDir: string;
9
22
  /** Absolute path to the islands directory (used by the interpolation plugin). */
@@ -14,6 +27,8 @@ export interface ClientBuildOptions {
14
27
  base?: string;
15
28
  /** Optional log prefix. */
16
29
  logPrefix?: string;
30
+ /** Suppress bundle logs (kit's and Vite's); errors still surface. */
31
+ quiet?: boolean;
17
32
  /**
18
33
  * How the legacy interpolation transform is handled (default: "auto").
19
34
  * With a Elur core that supports partial attribute interpolation natively
@@ -36,6 +51,14 @@ export interface ClientBuildResult {
36
51
  * transformed before reaching the browser.
37
52
  */
38
53
  export declare function buildClientBundle(options: ClientBuildOptions): Promise<ClientBuildResult>;
54
+ export declare function loadUserConfig(path: string, _root: string): Promise<InlineConfig>;
55
+ /**
56
+ * Resolves a user Vite config's `build.rollupOptions.input` to a list of
57
+ * absolute entry paths. Used to detect whether the bundle will emit the
58
+ * generated router module as its own chunk (split build) or not (legacy
59
+ * single-entry bundle — the router stays embedded in the entry).
60
+ */
61
+ export declare function resolveClientInputs(userConfigPath: string, root: string): Promise<string[]>;
39
62
  export interface AtomicStageOptions {
40
63
  /** Final destination directory (absolute). */
41
64
  outDir: string;
@@ -0,0 +1,41 @@
1
+ export interface CacheEntry {
2
+ html: string;
3
+ generatedAt: number;
4
+ revalidate: number;
5
+ tags?: string[];
6
+ version?: string;
7
+ }
8
+ export interface CacheWriteOptions {
9
+ revalidate: number;
10
+ tags?: string[];
11
+ version?: string;
12
+ }
13
+ export interface CacheAdapter {
14
+ get(key: string): Promise<CacheEntry | null>;
15
+ set(key: string, value: CacheEntry, options: CacheWriteOptions): Promise<void>;
16
+ delete(key: string): Promise<void>;
17
+ invalidateTags(tags: readonly string[]): Promise<void>;
18
+ }
19
+ /** Computes a SHA-256 key from a normalized identity string. */
20
+ export declare function cacheKey(...parts: string[]): string;
21
+ export interface FsCacheAdapterOptions {
22
+ cacheDir: string;
23
+ /** Max entries before cleanup runs. Default: 1000. */
24
+ maxEntries?: number;
25
+ /** Max age in ms for entries. Default: 24h. */
26
+ maxAgeMs?: number;
27
+ }
28
+ export declare function createFsCacheAdapter(options: FsCacheAdapterOptions): CacheAdapter;
29
+ /**
30
+ * Gets a cached entry. If the entry is stale (past revalidate), serves it
31
+ * immediately and triggers a background revalidation.
32
+ *
33
+ * @param adapter The cache adapter.
34
+ * @param key The cache key.
35
+ * @param revalidate The revalidation function (called if stale or missing).
36
+ * @returns The cache entry (fresh or stale), or null if missing.
37
+ */
38
+ export declare function getWithSWR(adapter: CacheAdapter, key: string, revalidate: () => Promise<CacheEntry | null>): Promise<{
39
+ entry: CacheEntry | null;
40
+ stale: boolean;
41
+ }>;
@@ -0,0 +1,41 @@
1
+ export interface CacheEntry {
2
+ html: string;
3
+ generatedAt: number;
4
+ revalidate: number;
5
+ tags?: string[];
6
+ version?: string;
7
+ }
8
+ export interface CacheWriteOptions {
9
+ revalidate: number;
10
+ tags?: string[];
11
+ version?: string;
12
+ }
13
+ export interface CacheAdapter {
14
+ get(key: string): Promise<CacheEntry | null>;
15
+ set(key: string, value: CacheEntry, options: CacheWriteOptions): Promise<void>;
16
+ delete(key: string): Promise<void>;
17
+ invalidateTags(tags: readonly string[]): Promise<void>;
18
+ }
19
+ /** Computes a SHA-256 key from a normalized identity string. */
20
+ export declare function cacheKey(...parts: string[]): string;
21
+ export interface FsCacheAdapterOptions {
22
+ cacheDir: string;
23
+ /** Max entries before cleanup runs. Default: 1000. */
24
+ maxEntries?: number;
25
+ /** Max age in ms for entries. Default: 24h. */
26
+ maxAgeMs?: number;
27
+ }
28
+ export declare function createFsCacheAdapter(options: FsCacheAdapterOptions): CacheAdapter;
29
+ /**
30
+ * Gets a cached entry. If the entry is stale (past revalidate), serves it
31
+ * immediately and triggers a background revalidation.
32
+ *
33
+ * @param adapter The cache adapter.
34
+ * @param key The cache key.
35
+ * @param revalidate The revalidation function (called if stale or missing).
36
+ * @returns The cache entry (fresh or stale), or null if missing.
37
+ */
38
+ export declare function getWithSWR(adapter: CacheAdapter, key: string, revalidate: () => Promise<CacheEntry | null>): Promise<{
39
+ entry: CacheEntry | null;
40
+ stale: boolean;
41
+ }>;
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../invalidation-CFpNQUv6.cjs"),t=require("../cache-X1n4Ossu.cjs"),n=require("../adapter-Dz2hzR36.cjs");function r(e){let t=e.client,n=e.prefix??`elur-kit:`,r=e=>`${n}data:${e}`,i=e=>`${n}tag:${e}`;async function a(e){let n=await t.get(r(e));if(!n)return null;try{return JSON.parse(n)}catch{return null}}async function o(e,n,a){let o={html:n.html,generatedAt:n.generatedAt??Date.now(),revalidate:a.revalidate,tags:a.tags,version:a.version},s=r(e),c=JSON.stringify(o);if(a.revalidate>0?await t.set(s,c,{PX:a.revalidate*1e3}):await t.set(s,c),a.tags&&a.tags.length>0&&t.sadd&&t.srem)for(let e of a.tags)await t.sadd(i(e),s)}async function s(e){await t.del(r(e))}async function c(e){if(e.length!==0){if(t.smembers&&t.srem){let n=new Set;for(let r of e){let e=await t.smembers(i(r));for(let t of e)n.add(t);await t.del(i(r))}n.size>0&&await t.del([...n])}else{let r=await t.keys(`${n}data:*`);for(let n of r){let r=await t.get(n);if(r)try{JSON.parse(r).tags?.some(t=>e.includes(t))&&await t.del(n)}catch{}}}}}return{get:a,set:o,delete:s,invalidateTags:c}}function i(e){let t=e.namespace,n=e.prefix??`elur-kit:`,r=e=>`${n}data:${e}`,i=e=>`${n}tag:${e}`;async function a(e){let n=await t.get(i(e));if(!n)return[];try{return JSON.parse(n)}catch{return[]}}async function o(e,n){await t.put(i(e),JSON.stringify(n))}async function s(e){let n=await t.get(r(e));if(!n)return null;try{return JSON.parse(n)}catch{return null}}async function c(e,n,i){let s={html:n.html,generatedAt:n.generatedAt??Date.now(),revalidate:i.revalidate,tags:i.tags,version:i.version},c=r(e),l=JSON.stringify(s);if(i.revalidate>0?await t.put(c,l,{expirationTtl:i.revalidate}):await t.put(c,l),i.tags&&i.tags.length>0)for(let e of i.tags){let t=await a(e);t.includes(c)||(t.push(c),await o(e,t))}}async function l(e){await t.delete(r(e))}async function u(e){if(e.length!==0)for(let n of e){let e=await a(n);for(let n of e)await t.delete(n);await t.delete(i(n))}}return{get:s,set:c,delete:l,invalidateTags:u}}exports.CacheInvalidator=e.t,exports.DEFAULT_CACHE_POLICY=e.i,exports.cacheKey=n.n,exports.clearCache=t.t,exports.connectCacheAdapter=e.n,exports.createCloudflareKVCacheAdapter=i,exports.createFsCacheAdapter=n.r,exports.createRedisCacheAdapter=r,exports.defaultInvalidator=e.r,exports.getCachedHtml=t.n,exports.getWithSWR=n.i,exports.isStale=t.r,exports.normalizeCachePolicy=e.a,exports.setCachedHtml=t.i,exports.shouldCachePublic=e.o;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/cache/redis-adapter.ts"],"sourcesContent":["// --- Redis / Upstash / Cloudflare KV Cache Adapter (v2.1 — Fix #3) ---\n//\n// Pluggable cache adapter for serverless and distributed deployments.\n// Implements the same CacheAdapter interface as the filesystem adapter, so\n// it can be dropped in via config without changing application code.\n//\n// Supports any Redis-compatible client (node-redis, ioredis, Upstash REST,\n// Cloudflare KV via @upstash/redis or direct API).\n\nimport type { CacheAdapter, CacheEntry, CacheWriteOptions } from \"./adapter.js\";\n\n// ─── Redis Cache Adapter ────────────────────────────────────────────────────\n\nexport interface RedisCacheAdapterOptions {\n /**\n * Redis client with get/set/del commands.\n * Compatible with node-redis, ioredis, and Upstash.\n */\n client: RedisClient;\n /** Key prefix to namespace cache entries. Default: \"elur-kit:\". */\n prefix?: string;\n}\n\nexport interface RedisClient {\n get(key: string): Promise<string | null>;\n set(key: string, value: string, opts?: { EX?: number; PX?: number; NX?: boolean }): Promise<unknown>;\n del(key: string | string[]): Promise<number>;\n keys(pattern: string): Promise<string[]>;\n srem?(key: string, ...members: string[]): Promise<number>;\n smembers?(key: string): Promise<string[]>;\n sadd?(key: string, ...members: string[]): Promise<number>;\n}\n\nexport function createRedisCacheAdapter(options: RedisCacheAdapterOptions): CacheAdapter {\n const client = options.client;\n const prefix = options.prefix ?? \"elur-kit:\";\n\n const dataKey = (key: string) => `${prefix}data:${key}`;\n const tagKey = (tag: string) => `${prefix}tag:${tag}`;\n\n async function get(key: string): Promise<CacheEntry | null> {\n const raw = await client.get(dataKey(key));\n if (!raw) return null;\n try {\n return JSON.parse(raw) as CacheEntry;\n } catch {\n return null;\n }\n }\n\n async function set(key: string, value: CacheEntry, opts: CacheWriteOptions): Promise<void> {\n const entry: CacheEntry = {\n html: value.html,\n generatedAt: value.generatedAt ?? Date.now(),\n revalidate: opts.revalidate,\n tags: opts.tags,\n version: opts.version,\n };\n const fullKey = dataKey(key);\n const serialized = JSON.stringify(entry);\n\n // Set TTL on the Redis key if revalidate is set (convert seconds to ms for PX).\n if (opts.revalidate > 0) {\n await client.set(fullKey, serialized, { PX: opts.revalidate * 1000 });\n } else {\n await client.set(fullKey, serialized);\n }\n\n // Update tag index using Redis sets if available.\n if (opts.tags && opts.tags.length > 0 && client.sadd && client.srem) {\n for (const tag of opts.tags) {\n await client.sadd(tagKey(tag), fullKey);\n }\n }\n }\n\n async function del(key: string): Promise<void> {\n await client.del(dataKey(key));\n }\n\n async function invalidateTags(tags: readonly string[]): Promise<void> {\n if (tags.length === 0) return;\n\n if (client.smembers && client.srem) {\n // Use Redis sets for O(1) tag lookup.\n const keysToDelete = new Set<string>();\n for (const tag of tags) {\n const members = await client.smembers(tagKey(tag));\n for (const m of members) keysToDelete.add(m);\n await client.del(tagKey(tag));\n }\n if (keysToDelete.size > 0) {\n await client.del([...keysToDelete]);\n }\n } else {\n // Fallback: scan all data keys and check tags in the entry.\n const allKeys = await client.keys(`${prefix}data:*`);\n for (const fullKey of allKeys) {\n const raw = await client.get(fullKey);\n if (!raw) continue;\n try {\n const entry = JSON.parse(raw) as CacheEntry;\n if (entry.tags?.some((t) => tags.includes(t))) {\n await client.del(fullKey);\n }\n } catch {\n // skip corrupt entries\n }\n }\n }\n }\n\n return { get, set, delete: del, invalidateTags };\n}\n\n// ─── Cloudflare KV Cache Adapter ────────────────────────────────────────────\n\nexport interface CloudflareKVAdapterOptions {\n /**\n * Cloudflare KV namespace binding (from wrangler.toml env binding).\n * Must implement `get`, `put`, and `delete` methods.\n */\n namespace: CloudflareKVNamespace;\n /** Key prefix to namespace cache entries. Default: \"elur-kit:\". */\n prefix?: string;\n}\n\nexport interface CloudflareKVNamespace {\n get(key: string): Promise<string | null>;\n put(key: string, value: string, options?: { expirationTtl?: number }): Promise<void>;\n delete(key: string): Promise<void>;\n list(options?: { prefix?: string }): Promise<{ keys: { name: string; metadata?: unknown }[] }>;\n}\n\nexport function createCloudflareKVCacheAdapter(options: CloudflareKVAdapterOptions): CacheAdapter {\n const kv = options.namespace;\n const prefix = options.prefix ?? \"elur-kit:\";\n\n const dataKey = (key: string) => `${prefix}data:${key}`;\n const tagKey = (tag: string) => `${prefix}tag:${tag}`;\n\n // KV doesn't have sets, so we store tag → keys as a JSON string.\n async function loadTagKeys(tag: string): Promise<string[]> {\n const raw = await kv.get(tagKey(tag));\n if (!raw) return [];\n try {\n return JSON.parse(raw) as string[];\n } catch {\n return [];\n }\n }\n\n async function saveTagKeys(tag: string, keys: string[]): Promise<void> {\n await kv.put(tagKey(tag), JSON.stringify(keys));\n }\n\n async function get(key: string): Promise<CacheEntry | null> {\n const raw = await kv.get(dataKey(key));\n if (!raw) return null;\n try {\n return JSON.parse(raw) as CacheEntry;\n } catch {\n return null;\n }\n }\n\n async function set(key: string, value: CacheEntry, opts: CacheWriteOptions): Promise<void> {\n const entry: CacheEntry = {\n html: value.html,\n generatedAt: value.generatedAt ?? Date.now(),\n revalidate: opts.revalidate,\n tags: opts.tags,\n version: opts.version,\n };\n const fullKey = dataKey(key);\n const serialized = JSON.stringify(entry);\n\n // KV supports expirationTtl in seconds.\n if (opts.revalidate > 0) {\n await kv.put(fullKey, serialized, { expirationTtl: opts.revalidate });\n } else {\n await kv.put(fullKey, serialized);\n }\n\n // Update tag index.\n if (opts.tags && opts.tags.length > 0) {\n for (const tag of opts.tags) {\n const existing = await loadTagKeys(tag);\n if (!existing.includes(fullKey)) {\n existing.push(fullKey);\n await saveTagKeys(tag, existing);\n }\n }\n }\n }\n\n async function del(key: string): Promise<void> {\n await kv.delete(dataKey(key));\n }\n\n async function invalidateTags(tags: readonly string[]): Promise<void> {\n if (tags.length === 0) return;\n for (const tag of tags) {\n const keys = await loadTagKeys(tag);\n for (const fullKey of keys) {\n await kv.delete(fullKey);\n }\n await kv.delete(tagKey(tag));\n }\n }\n\n return { get, set, delete: del, invalidateTags };\n}\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { type CacheAdapter, type CacheEntry, type CacheWriteOptions, type FsCacheAdapterOptions, createFsCacheAdapter, cacheKey, getWithSWR, } from "./adapter.js";
2
+ export { type RedisCacheAdapterOptions, type RedisClient, createRedisCacheAdapter, type CloudflareKVAdapterOptions, type CloudflareKVNamespace, createCloudflareKVCacheAdapter, } from "./redis-adapter.js";
3
+ export { type CacheMode, type CachePolicy, DEFAULT_CACHE_POLICY, normalizeCachePolicy, shouldCachePublic, } from "./policy.js";
4
+ export { type InvalidationEvent, type InvalidationListener, CacheInvalidator, defaultInvalidator, connectCacheAdapter, } from "./invalidation.js";
5
+ export { getCachedHtml, setCachedHtml, isStale, clearCache, type CacheOptions, } from "../cache.js";
@@ -0,0 +1,5 @@
1
+ export { type CacheAdapter, type CacheEntry, type CacheWriteOptions, type FsCacheAdapterOptions, createFsCacheAdapter, cacheKey, getWithSWR, } from "./adapter.js";
2
+ export { type RedisCacheAdapterOptions, type RedisClient, createRedisCacheAdapter, type CloudflareKVAdapterOptions, type CloudflareKVNamespace, createCloudflareKVCacheAdapter, } from "./redis-adapter.js";
3
+ export { type CacheMode, type CachePolicy, DEFAULT_CACHE_POLICY, normalizeCachePolicy, shouldCachePublic, } from "./policy.js";
4
+ export { type InvalidationEvent, type InvalidationListener, CacheInvalidator, defaultInvalidator, connectCacheAdapter, } from "./invalidation.js";
5
+ export { getCachedHtml, setCachedHtml, isStale, clearCache, type CacheOptions, } from "../cache.js";