@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
@@ -0,0 +1,30 @@
1
+ import type { PageRoute } from "../router/route-scanner.js";
2
+ import type { BuildConfig } from "../build/build.js";
3
+ export interface StreamResponseOptions {
4
+ route: PageRoute;
5
+ params: Record<string, string | string[]>;
6
+ searchParams: URLSearchParams;
7
+ config: Pick<BuildConfig, "lang" | "clientEntry" | "renderEndpoint" | "router" | "js">;
8
+ actions?: Record<string, string[]>;
9
+ importer?: (path: string) => Promise<unknown>;
10
+ request?: Request;
11
+ /** AbortSignal from the host (client disconnect). */
12
+ signal?: AbortSignal;
13
+ }
14
+ /**
15
+ * Creates a streaming Response that sends the shell + loading fallback first,
16
+ * then appends the resolved content.
17
+ *
18
+ * If the route has no loading boundary, falls back to a normal renderPage.
19
+ */
20
+ export declare function createStreamingResponse(options: StreamResponseOptions): Promise<Response>;
21
+ /**
22
+ * Buffered fallback for adapters without streaming support.
23
+ * Renders the full page and returns it as a single Response.
24
+ */
25
+ export declare function createBufferedResponse(options: StreamResponseOptions): Promise<Response>;
26
+ /**
27
+ * Checks if the host runtime supports streaming responses.
28
+ * Node, Bun, and modern edge runtimes do. Some serverless platforms may not.
29
+ */
30
+ export { supportsStreaming } from "../runtime/capabilities.js";
@@ -0,0 +1,30 @@
1
+ import type { PageRoute } from "../router/route-scanner.js";
2
+ import type { BuildConfig } from "../build/build.js";
3
+ export interface StreamResponseOptions {
4
+ route: PageRoute;
5
+ params: Record<string, string | string[]>;
6
+ searchParams: URLSearchParams;
7
+ config: Pick<BuildConfig, "lang" | "clientEntry" | "renderEndpoint" | "router" | "js">;
8
+ actions?: Record<string, string[]>;
9
+ importer?: (path: string) => Promise<unknown>;
10
+ request?: Request;
11
+ /** AbortSignal from the host (client disconnect). */
12
+ signal?: AbortSignal;
13
+ }
14
+ /**
15
+ * Creates a streaming Response that sends the shell + loading fallback first,
16
+ * then appends the resolved content.
17
+ *
18
+ * If the route has no loading boundary, falls back to a normal renderPage.
19
+ */
20
+ export declare function createStreamingResponse(options: StreamResponseOptions): Promise<Response>;
21
+ /**
22
+ * Buffered fallback for adapters without streaming support.
23
+ * Renders the full page and returns it as a single Response.
24
+ */
25
+ export declare function createBufferedResponse(options: StreamResponseOptions): Promise<Response>;
26
+ /**
27
+ * Checks if the host runtime supports streaming responses.
28
+ * Node, Bun, and modern edge runtimes do. Some serverless platforms may not.
29
+ */
30
+ export { supportsStreaming } from "../runtime/capabilities.js";
@@ -12,13 +12,18 @@ export interface StreamingPageOptions {
12
12
  /**
13
13
  * Render a page shell that shows the loading boundary while the real content
14
14
  * is fetched and injected by the client.
15
+ *
16
+ * @deprecated Legacy shell + client-fetch approach, only used by the
17
+ * deprecated `createSsrServer`. Real streaming SSR (shell first, resolved
18
+ * content streamed as a swap chunk) lives in `createStreamingResponse`
19
+ * (`src/ssr/stream-response.ts`, exported from the package root).
15
20
  */
16
21
  export declare function renderStreamingPage(options: StreamingPageOptions): Promise<string>;
17
22
  export interface RenderPageBodyOptions {
18
23
  routes: ScannedRoutes;
19
24
  pathname: string;
20
25
  searchParams: URLSearchParams;
21
- config: Pick<BuildConfig, "lang" | "clientEntry">;
26
+ config: Pick<BuildConfig, "lang" | "clientEntry" | "router" | "js">;
22
27
  actions?: Record<string, string[]>;
23
28
  importer?: (path: string) => Promise<unknown>;
24
29
  request?: Request;
@@ -34,6 +39,16 @@ export interface RenderPageBodyResult {
34
39
  clearActionErrorCookie?: string;
35
40
  /** `<head>` tags (title, meta, OG, twitter) for the SPA router to merge. */
36
41
  head?: string;
42
+ /**
43
+ * Serialized contents of `<script id="elur-data">` for this page, when the
44
+ * shell emitted it. Lets the SPA router refresh the inert data script after
45
+ * navigation instead of leaving the initial page's data frozen.
46
+ */
47
+ data?: string;
48
+ /**
49
+ * Serialized contents of `<script id="elur-actions">`, when emitted.
50
+ */
51
+ actions?: string;
37
52
  /** First-class Response when a loader threw one (A-22). */
38
53
  response?: Response;
39
54
  }
@@ -12,13 +12,18 @@ export interface StreamingPageOptions {
12
12
  /**
13
13
  * Render a page shell that shows the loading boundary while the real content
14
14
  * is fetched and injected by the client.
15
+ *
16
+ * @deprecated Legacy shell + client-fetch approach, only used by the
17
+ * deprecated `createSsrServer`. Real streaming SSR (shell first, resolved
18
+ * content streamed as a swap chunk) lives in `createStreamingResponse`
19
+ * (`src/ssr/stream-response.ts`, exported from the package root).
15
20
  */
16
21
  export declare function renderStreamingPage(options: StreamingPageOptions): Promise<string>;
17
22
  export interface RenderPageBodyOptions {
18
23
  routes: ScannedRoutes;
19
24
  pathname: string;
20
25
  searchParams: URLSearchParams;
21
- config: Pick<BuildConfig, "lang" | "clientEntry">;
26
+ config: Pick<BuildConfig, "lang" | "clientEntry" | "router" | "js">;
22
27
  actions?: Record<string, string[]>;
23
28
  importer?: (path: string) => Promise<unknown>;
24
29
  request?: Request;
@@ -34,6 +39,16 @@ export interface RenderPageBodyResult {
34
39
  clearActionErrorCookie?: string;
35
40
  /** `<head>` tags (title, meta, OG, twitter) for the SPA router to merge. */
36
41
  head?: string;
42
+ /**
43
+ * Serialized contents of `<script id="elur-data">` for this page, when the
44
+ * shell emitted it. Lets the SPA router refresh the inert data script after
45
+ * navigation instead of leaving the initial page's data frozen.
46
+ */
47
+ data?: string;
48
+ /**
49
+ * Serialized contents of `<script id="elur-actions">`, when emitted.
50
+ */
51
+ actions?: string;
37
52
  /** First-class Response when a loader threw one (A-22). */
38
53
  response?: Response;
39
54
  }
@@ -1,4 +1,4 @@
1
- const e=require("./errors-0X7pCFNU.cjs"),t=require("./node-http-DhxguYyz.cjs");var n=e.u({RouteNotFoundError:()=>s,renderPageBody:()=>c,renderStreamingPage:()=>o}),r=e=>import(e);function i(e,t){return e.replace(/:([a-zA-Z0-9_]+)(\*)?/g,(e,n,r)=>{let i=t[n];return i==null?``:r&&Array.isArray(i)?i.join(`/`):String(i)})}function a(e,t){return`<script type="module">${`
1
+ const e=require("./rolldown-runtime-BIInC43l.cjs"),t=require("./node-http-Uct7DhmN.cjs");var n=e.t({RouteNotFoundError:()=>s,renderPageBody:()=>c,renderStreamingPage:()=>o}),r=e=>import(e);function i(e,t){return e.replace(/:([a-zA-Z0-9_]+)(\*)?/g,(e,n,r)=>{let i=t[n];return i==null?``:r&&Array.isArray(i)?i.join(`/`):String(i)})}function a(e,t){return`<script type="module">${`
2
2
  async function __elurJsStreamRender() {
3
3
  try {
4
4
  const url = "/__elur-js/render?page=" + encodeURIComponent(${JSON.stringify(e)}) + "&search=" + encodeURIComponent(${JSON.stringify(t)});
@@ -13,5 +13,5 @@ const e=require("./errors-0X7pCFNU.cjs"),t=require("./node-http-DhxguYyz.cjs");v
13
13
  }
14
14
  }
15
15
  __elurJsStreamRender();
16
- `}<\/script>`}async function o(e){let{route:n,params:o,searchParams:s,config:c,importer:l=r,actions:u}=e;if(!n.loadingPath)throw Error(`Cannot stream a page without a loading.ts boundary`);let{default:d}=await l(n.loadingPath),f=`<div id="elur-loading">${await t.v(()=>d())}</div>${a(i(n.path,o),s.toString())}`,p={},m=[],h=[];if(n.layouts.length>0){let t=n.layouts[0],r=t.replace(/layout\.ts$/,`layout.data.ts`);if(r!==t)try{let t=await l(r),n=t.load?await t.load({params:o,searchParams:s,request:e.request}):void 0;if(n&&typeof n==`object`){let e=n.htmlAttributes;e&&Object.assign(p,e);let t=n.headScripts;Array.isArray(t)&&m.push(...t);let r=n.headLinks;Array.isArray(r)&&h.push(...r)}}catch{}}return t._({title:`Loading...`,lang:c.lang,body:f,data:{__elur_js_streaming:!0,page:n.path},actions:u,htmlAttributes:p,headScripts:m,headLinks:h,clientEntry:c.clientEntry})}var s=class extends Error{constructor(e){super(`No route found for ${e}`),this.name=`RouteNotFoundError`}};async function c(e){let{routes:n,pathname:i,searchParams:a,config:o,actions:c,importer:l=r,request:u}=e,d=t.o(i,n.pages);if(!d)throw new s(i);let f=await t.l({route:d.route,params:d.params,searchParams:a,config:o,actions:c,importer:l,request:u});if(f.response)return{body:``,title:``,response:f.response};let p=f.html.match(/<div id="app">([\s\S]*)<\/div>\s*(<script|$)/),m=p?p[1].trim():f.html,h=f.html.match(/<title[^>]*>([^<]*)<\/title>/);return{body:m,title:h?h[1]:f.resolvedTitle??``,fullHtml:f.html,clearActionErrorCookie:f.clearActionErrorCookie,head:f.head}}Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return s}});
17
- //# sourceMappingURL=stream-DmZjYqHm.cjs.map
16
+ `}<\/script>`}async function o(e){let{route:n,params:o,searchParams:s,config:c,importer:l=r,actions:u}=e;if(!n.loadingPath)throw Error(`Cannot stream a page without a loading.ts boundary`);let{default:d}=await l(n.loadingPath),f=`<div id="elur-loading">${await t.T(()=>d())}</div>${a(i(n.path,o),s.toString())}`,p={},m=[],h=[];if(n.layouts.length>0){let t=n.layouts[0],r=t.replace(/layout\.ts$/,`layout.data.ts`);if(r!==t)try{let t=await l(r),n=t.load?await t.load({params:o,searchParams:s,request:e.request}):void 0;if(n&&typeof n==`object`){let e=n.htmlAttributes;e&&Object.assign(p,e);let t=n.headScripts;Array.isArray(t)&&m.push(...t);let r=n.headLinks;Array.isArray(r)&&h.push(...r)}}catch{}}return t.S({title:`Loading...`,lang:c.lang,body:f,data:{__elur_js_streaming:!0,page:n.path},actions:u,htmlAttributes:p,headScripts:m,headLinks:h,clientEntry:c.clientEntry})}var s=class extends Error{constructor(e){super(`No route found for ${e}`),this.name=`RouteNotFoundError`}};async function c(e){let{routes:n,pathname:i,searchParams:a,config:o,actions:c,importer:l=r,request:u}=e,d=t.u(i,n.pages);if(!d)throw new s(i);let f=await t.p({route:d.route,params:d.params,searchParams:a,config:o,actions:c,importer:l,request:u});if(f.response)return{body:``,title:``,response:f.response};let p=t.C(f.html)?.trim()??f.html.match(/<div id="app">([\s\S]*)<\/div>\s*(<script|$)/)?.[1]?.trim()??f.html,m=f.html.match(/<title[^>]*>([^<]*)<\/title>/);return{body:p,title:m?m[1]:f.resolvedTitle??``,fullHtml:f.html,clearActionErrorCookie:f.clearActionErrorCookie,head:f.head,data:f.data===void 0?void 0:t.w(f.data),actions:c&&Object.keys(c).length>0?t.w(c):void 0}}Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return s}});
17
+ //# sourceMappingURL=stream-Cg-xYG82.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-Cg-xYG82.cjs","names":[],"sources":["../../src/ssr/stream.ts"],"sourcesContent":["import type { ElurTemplate } from \"@elurjs/core\";\nimport { renderToString } from \"../render/render-to-string.js\";\nimport { documentShell, extractAppBody, serializeData } from \"../build/document-shell.js\";\nimport type { PageRoute, ScannedRoutes } from \"../router/route-scanner.js\";\nimport type { BuildConfig } from \"../build/build.js\";\nimport type { PageDataLoad } from \"../types.js\";\nimport { matchRoute } from \"./match.js\";\nimport { renderPage } from \"./render.js\";\n\nexport interface StreamingPageOptions {\n route: PageRoute;\n params: Record<string, string | string[]>;\n searchParams: URLSearchParams;\n config: Pick<BuildConfig, \"lang\" | \"clientEntry\">;\n importer?: (path: string) => Promise<unknown>;\n actions?: Record<string, string[]>;\n request?: Request;\n}\n\nconst defaultImport = (path: string) => import(path);\n\n/** Builds the concrete URL path for a route pattern given matched params. */\nfunction buildConcretePath(\n routePath: string,\n params: Record<string, string | string[]>,\n): string {\n return routePath.replace(/:([a-zA-Z0-9_]+)(\\*)?/g, (_m, name: string, catchAll?: string) => {\n const value = params[name];\n if (value === undefined || value === null) return \"\";\n return catchAll ? (Array.isArray(value) ? value.join(\"/\") : String(value)) : String(value);\n });\n}\n\nfunction streamingScript(page: string, search: string): string {\n const src = `\n async function __elurJsStreamRender() {\n try {\n const url = \"/__elur-js/render?page=\" + encodeURIComponent(${JSON.stringify(page)}) + \"&search=\" + encodeURIComponent(${JSON.stringify(search)});\n const res = await fetch(url);\n if (!res.ok) throw new Error(\"Streaming render failed: \" + res.status);\n const html = await res.text();\n const app = document.getElementById(\"app\");\n if (app) app.innerHTML = html;\n document.dispatchEvent(new CustomEvent(\"elur:rendered\"));\n } catch (err) {\n console.error(\"[elur-kit] streaming render failed\", err);\n }\n }\n __elurJsStreamRender();\n `;\n return `<script type=\"module\">${src}</script>`;\n}\n\n/**\n * Render a page shell that shows the loading boundary while the real content\n * is fetched and injected by the client.\n *\n * @deprecated Legacy shell + client-fetch approach, only used by the\n * deprecated `createSsrServer`. Real streaming SSR (shell first, resolved\n * content streamed as a swap chunk) lives in `createStreamingResponse`\n * (`src/ssr/stream-response.ts`, exported from the package root).\n */\nexport async function renderStreamingPage(options: StreamingPageOptions): Promise<string> {\n const { route, params, searchParams, config, importer = defaultImport, actions } = options;\n if (!route.loadingPath) {\n throw new Error(\"Cannot stream a page without a loading.ts boundary\");\n }\n\n const { default: Loading } = (await importer(route.loadingPath)) as {\n default: () => ElurTemplate;\n };\n\n const loadingBody = await renderToString(() => Loading());\n const concretePath = buildConcretePath(route.path, params);\n const body = `<div id=\"elur-loading\">${loadingBody}</div>${streamingScript(concretePath, searchParams.toString())}`;\n\n // Apply <html> attributes and head scripts (e.g. data-theme and the no-flash\n // theme script) from the root layout loader so the shell paints correctly\n // before the real content arrives.\n const htmlAttributes: Record<string, string> = {};\n const headScripts: string[] = [];\n const headLinks: string[] = [];\n if (route.layouts.length > 0) {\n const rootLayout = route.layouts[0];\n const dataPath = rootLayout.replace(/layout\\.ts$/, \"layout.data.ts\");\n if (dataPath !== rootLayout) {\n try {\n const mod = (await importer(dataPath)) as { load?: PageDataLoad };\n const layoutData = mod.load ? await mod.load({ params, searchParams, request: options.request }) : undefined;\n if (layoutData && typeof layoutData === \"object\") {\n const attrs = (layoutData as { htmlAttributes?: Record<string, string> }).htmlAttributes;\n if (attrs) Object.assign(htmlAttributes, attrs);\n const scripts = (layoutData as { headScripts?: string[] }).headScripts;\n if (Array.isArray(scripts)) headScripts.push(...scripts);\n const links = (layoutData as { headLinks?: string[] }).headLinks;\n if (Array.isArray(links)) headLinks.push(...links);\n }\n } catch {\n // The root layout loader is optional; ignore failures here.\n }\n }\n }\n\n return documentShell({\n title: \"Loading...\",\n lang: config.lang,\n body,\n data: { __elur_js_streaming: true, page: route.path },\n actions,\n htmlAttributes,\n headScripts,\n headLinks,\n clientEntry: config.clientEntry,\n });\n}\n\nexport interface RenderPageBodyOptions {\n routes: ScannedRoutes;\n pathname: string;\n searchParams: URLSearchParams;\n config: Pick<BuildConfig, \"lang\" | \"clientEntry\" | \"router\" | \"js\">;\n actions?: Record<string, string[]>;\n importer?: (path: string) => Promise<unknown>;\n request?: Request;\n}\n\nexport interface RenderPageBodyResult {\n /** Inner HTML body for the page (without the document shell). */\n body: string;\n /** Page title extracted from the rendered shell. */\n title: string;\n /** Full rendered document shell (used for ISR caching). */\n fullHtml?: string;\n /** `Set-Cookie` value that clears a consumed action error cookie. */\n clearActionErrorCookie?: string;\n /** `<head>` tags (title, meta, OG, twitter) for the SPA router to merge. */\n head?: string;\n /**\n * Serialized contents of `<script id=\"elur-data\">` for this page, when the\n * shell emitted it. Lets the SPA router refresh the inert data script after\n * navigation instead of leaving the initial page's data frozen.\n */\n data?: string;\n /**\n * Serialized contents of `<script id=\"elur-actions\">`, when emitted.\n */\n actions?: string;\n /** First-class Response when a loader threw one (A-22). */\n response?: Response;\n}\n\n/** Thrown by `renderPageBody` when the requested path has no matching route. */\nexport class RouteNotFoundError extends Error {\n constructor(pathname: string) {\n super(`No route found for ${pathname}`);\n this.name = \"RouteNotFoundError\";\n }\n}\n\n/**\n * Render only the inner HTML body for a page. Used by the streaming endpoint\n * to inject the real content into the shell.\n */\nexport async function renderPageBody(options: RenderPageBodyOptions): Promise<RenderPageBodyResult> {\n const { routes, pathname, searchParams, config, actions, importer = defaultImport, request } = options;\n const match = matchRoute(pathname, routes.pages);\n if (!match) {\n throw new RouteNotFoundError(pathname);\n }\n\n const result = await renderPage({\n route: match.route,\n params: match.params,\n searchParams,\n config,\n actions,\n importer,\n request,\n });\n\n // If a loader threw a Response (redirect, 404, etc.), propagate it (A-22).\n if (result.response) {\n return {\n body: \"\",\n title: \"\",\n response: result.response,\n };\n }\n\n const body = extractAppBody(result.html)?.trim()\n ?? result.html.match(/<div id=\"app\">([\\s\\S]*)<\\/div>\\s*(<script|$)/)?.[1]?.trim()\n ?? result.html;\n const titleMatch = result.html.match(/<title[^>]*>([^<]*)<\\/title>/);\n return {\n body,\n title: titleMatch ? titleMatch[1] : result.resolvedTitle ?? \"\",\n fullHtml: result.html,\n clearActionErrorCookie: result.clearActionErrorCookie,\n head: result.head,\n data: result.data !== undefined ? serializeData(result.data) : undefined,\n actions: actions && Object.keys(actions).length > 0 ? serializeData(actions) : undefined,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
+ import { C as t, S as n, T as r, p as i, u as a, w as o } from "./node-http-DVFcYeBS.js";
3
+ //#region src/ssr/stream.ts
4
+ var s = /* @__PURE__ */ e({
5
+ RouteNotFoundError: () => f,
6
+ renderPageBody: () => p,
7
+ renderStreamingPage: () => d
8
+ }), c = (e) => import(e);
9
+ function l(e, t) {
10
+ return e.replace(/:([a-zA-Z0-9_]+)(\*)?/g, (e, n, r) => {
11
+ let i = t[n];
12
+ return i == null ? "" : r && Array.isArray(i) ? i.join("/") : String(i);
13
+ });
14
+ }
15
+ function u(e, t) {
16
+ return `<script type="module">${`
17
+ async function __elurJsStreamRender() {
18
+ try {
19
+ const url = "/__elur-js/render?page=" + encodeURIComponent(${JSON.stringify(e)}) + "&search=" + encodeURIComponent(${JSON.stringify(t)});
20
+ const res = await fetch(url);
21
+ if (!res.ok) throw new Error("Streaming render failed: " + res.status);
22
+ const html = await res.text();
23
+ const app = document.getElementById("app");
24
+ if (app) app.innerHTML = html;
25
+ document.dispatchEvent(new CustomEvent("elur:rendered"));
26
+ } catch (err) {
27
+ console.error("[elur-kit] streaming render failed", err);
28
+ }
29
+ }
30
+ __elurJsStreamRender();
31
+ `}<\/script>`;
32
+ }
33
+ async function d(e) {
34
+ let { route: t, params: i, searchParams: a, config: o, importer: s = c, actions: d } = e;
35
+ if (!t.loadingPath) throw Error("Cannot stream a page without a loading.ts boundary");
36
+ let { default: f } = await s(t.loadingPath), p = `<div id="elur-loading">${await r(() => f())}</div>${u(l(t.path, i), a.toString())}`, m = {}, h = [], g = [];
37
+ if (t.layouts.length > 0) {
38
+ let n = t.layouts[0], r = n.replace(/layout\.ts$/, "layout.data.ts");
39
+ if (r !== n) try {
40
+ let t = await s(r), n = t.load ? await t.load({
41
+ params: i,
42
+ searchParams: a,
43
+ request: e.request
44
+ }) : void 0;
45
+ if (n && typeof n == "object") {
46
+ let e = n.htmlAttributes;
47
+ e && Object.assign(m, e);
48
+ let t = n.headScripts;
49
+ Array.isArray(t) && h.push(...t);
50
+ let r = n.headLinks;
51
+ Array.isArray(r) && g.push(...r);
52
+ }
53
+ } catch {}
54
+ }
55
+ return n({
56
+ title: "Loading...",
57
+ lang: o.lang,
58
+ body: p,
59
+ data: {
60
+ __elur_js_streaming: !0,
61
+ page: t.path
62
+ },
63
+ actions: d,
64
+ htmlAttributes: m,
65
+ headScripts: h,
66
+ headLinks: g,
67
+ clientEntry: o.clientEntry
68
+ });
69
+ }
70
+ var f = class extends Error {
71
+ constructor(e) {
72
+ super(`No route found for ${e}`), this.name = "RouteNotFoundError";
73
+ }
74
+ };
75
+ async function p(e) {
76
+ let { routes: n, pathname: r, searchParams: s, config: l, actions: u, importer: d = c, request: p } = e, m = a(r, n.pages);
77
+ if (!m) throw new f(r);
78
+ let h = await i({
79
+ route: m.route,
80
+ params: m.params,
81
+ searchParams: s,
82
+ config: l,
83
+ actions: u,
84
+ importer: d,
85
+ request: p
86
+ });
87
+ if (h.response) return {
88
+ body: "",
89
+ title: "",
90
+ response: h.response
91
+ };
92
+ let g = t(h.html)?.trim() ?? h.html.match(/<div id="app">([\s\S]*)<\/div>\s*(<script|$)/)?.[1]?.trim() ?? h.html, _ = h.html.match(/<title[^>]*>([^<]*)<\/title>/);
93
+ return {
94
+ body: g,
95
+ title: _ ? _[1] : h.resolvedTitle ?? "",
96
+ fullHtml: h.html,
97
+ clearActionErrorCookie: h.clearActionErrorCookie,
98
+ head: h.head,
99
+ data: h.data === void 0 ? void 0 : o(h.data),
100
+ actions: u && Object.keys(u).length > 0 ? o(u) : void 0
101
+ };
102
+ }
103
+ //#endregion
104
+ export { s as i, p as n, d as r, f as t };
105
+
106
+ //# sourceMappingURL=stream-D-ytogdu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-D-ytogdu.js","names":[],"sources":["../../src/ssr/stream.ts"],"sourcesContent":["import type { ElurTemplate } from \"@elurjs/core\";\nimport { renderToString } from \"../render/render-to-string.js\";\nimport { documentShell, extractAppBody, serializeData } from \"../build/document-shell.js\";\nimport type { PageRoute, ScannedRoutes } from \"../router/route-scanner.js\";\nimport type { BuildConfig } from \"../build/build.js\";\nimport type { PageDataLoad } from \"../types.js\";\nimport { matchRoute } from \"./match.js\";\nimport { renderPage } from \"./render.js\";\n\nexport interface StreamingPageOptions {\n route: PageRoute;\n params: Record<string, string | string[]>;\n searchParams: URLSearchParams;\n config: Pick<BuildConfig, \"lang\" | \"clientEntry\">;\n importer?: (path: string) => Promise<unknown>;\n actions?: Record<string, string[]>;\n request?: Request;\n}\n\nconst defaultImport = (path: string) => import(path);\n\n/** Builds the concrete URL path for a route pattern given matched params. */\nfunction buildConcretePath(\n routePath: string,\n params: Record<string, string | string[]>,\n): string {\n return routePath.replace(/:([a-zA-Z0-9_]+)(\\*)?/g, (_m, name: string, catchAll?: string) => {\n const value = params[name];\n if (value === undefined || value === null) return \"\";\n return catchAll ? (Array.isArray(value) ? value.join(\"/\") : String(value)) : String(value);\n });\n}\n\nfunction streamingScript(page: string, search: string): string {\n const src = `\n async function __elurJsStreamRender() {\n try {\n const url = \"/__elur-js/render?page=\" + encodeURIComponent(${JSON.stringify(page)}) + \"&search=\" + encodeURIComponent(${JSON.stringify(search)});\n const res = await fetch(url);\n if (!res.ok) throw new Error(\"Streaming render failed: \" + res.status);\n const html = await res.text();\n const app = document.getElementById(\"app\");\n if (app) app.innerHTML = html;\n document.dispatchEvent(new CustomEvent(\"elur:rendered\"));\n } catch (err) {\n console.error(\"[elur-kit] streaming render failed\", err);\n }\n }\n __elurJsStreamRender();\n `;\n return `<script type=\"module\">${src}</script>`;\n}\n\n/**\n * Render a page shell that shows the loading boundary while the real content\n * is fetched and injected by the client.\n *\n * @deprecated Legacy shell + client-fetch approach, only used by the\n * deprecated `createSsrServer`. Real streaming SSR (shell first, resolved\n * content streamed as a swap chunk) lives in `createStreamingResponse`\n * (`src/ssr/stream-response.ts`, exported from the package root).\n */\nexport async function renderStreamingPage(options: StreamingPageOptions): Promise<string> {\n const { route, params, searchParams, config, importer = defaultImport, actions } = options;\n if (!route.loadingPath) {\n throw new Error(\"Cannot stream a page without a loading.ts boundary\");\n }\n\n const { default: Loading } = (await importer(route.loadingPath)) as {\n default: () => ElurTemplate;\n };\n\n const loadingBody = await renderToString(() => Loading());\n const concretePath = buildConcretePath(route.path, params);\n const body = `<div id=\"elur-loading\">${loadingBody}</div>${streamingScript(concretePath, searchParams.toString())}`;\n\n // Apply <html> attributes and head scripts (e.g. data-theme and the no-flash\n // theme script) from the root layout loader so the shell paints correctly\n // before the real content arrives.\n const htmlAttributes: Record<string, string> = {};\n const headScripts: string[] = [];\n const headLinks: string[] = [];\n if (route.layouts.length > 0) {\n const rootLayout = route.layouts[0];\n const dataPath = rootLayout.replace(/layout\\.ts$/, \"layout.data.ts\");\n if (dataPath !== rootLayout) {\n try {\n const mod = (await importer(dataPath)) as { load?: PageDataLoad };\n const layoutData = mod.load ? await mod.load({ params, searchParams, request: options.request }) : undefined;\n if (layoutData && typeof layoutData === \"object\") {\n const attrs = (layoutData as { htmlAttributes?: Record<string, string> }).htmlAttributes;\n if (attrs) Object.assign(htmlAttributes, attrs);\n const scripts = (layoutData as { headScripts?: string[] }).headScripts;\n if (Array.isArray(scripts)) headScripts.push(...scripts);\n const links = (layoutData as { headLinks?: string[] }).headLinks;\n if (Array.isArray(links)) headLinks.push(...links);\n }\n } catch {\n // The root layout loader is optional; ignore failures here.\n }\n }\n }\n\n return documentShell({\n title: \"Loading...\",\n lang: config.lang,\n body,\n data: { __elur_js_streaming: true, page: route.path },\n actions,\n htmlAttributes,\n headScripts,\n headLinks,\n clientEntry: config.clientEntry,\n });\n}\n\nexport interface RenderPageBodyOptions {\n routes: ScannedRoutes;\n pathname: string;\n searchParams: URLSearchParams;\n config: Pick<BuildConfig, \"lang\" | \"clientEntry\" | \"router\" | \"js\">;\n actions?: Record<string, string[]>;\n importer?: (path: string) => Promise<unknown>;\n request?: Request;\n}\n\nexport interface RenderPageBodyResult {\n /** Inner HTML body for the page (without the document shell). */\n body: string;\n /** Page title extracted from the rendered shell. */\n title: string;\n /** Full rendered document shell (used for ISR caching). */\n fullHtml?: string;\n /** `Set-Cookie` value that clears a consumed action error cookie. */\n clearActionErrorCookie?: string;\n /** `<head>` tags (title, meta, OG, twitter) for the SPA router to merge. */\n head?: string;\n /**\n * Serialized contents of `<script id=\"elur-data\">` for this page, when the\n * shell emitted it. Lets the SPA router refresh the inert data script after\n * navigation instead of leaving the initial page's data frozen.\n */\n data?: string;\n /**\n * Serialized contents of `<script id=\"elur-actions\">`, when emitted.\n */\n actions?: string;\n /** First-class Response when a loader threw one (A-22). */\n response?: Response;\n}\n\n/** Thrown by `renderPageBody` when the requested path has no matching route. */\nexport class RouteNotFoundError extends Error {\n constructor(pathname: string) {\n super(`No route found for ${pathname}`);\n this.name = \"RouteNotFoundError\";\n }\n}\n\n/**\n * Render only the inner HTML body for a page. Used by the streaming endpoint\n * to inject the real content into the shell.\n */\nexport async function renderPageBody(options: RenderPageBodyOptions): Promise<RenderPageBodyResult> {\n const { routes, pathname, searchParams, config, actions, importer = defaultImport, request } = options;\n const match = matchRoute(pathname, routes.pages);\n if (!match) {\n throw new RouteNotFoundError(pathname);\n }\n\n const result = await renderPage({\n route: match.route,\n params: match.params,\n searchParams,\n config,\n actions,\n importer,\n request,\n });\n\n // If a loader threw a Response (redirect, 404, etc.), propagate it (A-22).\n if (result.response) {\n return {\n body: \"\",\n title: \"\",\n response: result.response,\n };\n }\n\n const body = extractAppBody(result.html)?.trim()\n ?? result.html.match(/<div id=\"app\">([\\s\\S]*)<\\/div>\\s*(<script|$)/)?.[1]?.trim()\n ?? result.html;\n const titleMatch = result.html.match(/<title[^>]*>([^<]*)<\\/title>/);\n return {\n body,\n title: titleMatch ? titleMatch[1] : result.resolvedTitle ?? \"\",\n fullHtml: result.html,\n clearActionErrorCookie: result.clearActionErrorCookie,\n head: result.head,\n data: result.data !== undefined ? serializeData(result.data) : undefined,\n actions: actions && Object.keys(actions).length > 0 ? serializeData(actions) : undefined,\n };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../node-http-DhxguYyz.cjs"),t=require("../route-scanner-JY6YrNH5.cjs"),n=require("../scan-CY2O9ty6.cjs"),r=require("../interpolation-plugin-TWDch8nn.cjs"),i=require("../scan-DXzYtmRQ.cjs"),a=require("../collections-VDy5g9p8.cjs");let o=require("node:fs/promises"),s=require("node:path");function c(c={}){let m=c.appDir??`src/app`,h=c.islandsDir??`src/islands`,g=c.contentDir??`src/content`,_=c.generatedEntry??`.elur/entry-client.ts`,v=c.clientEntry??`/_elur/entry-client.js`,y=c.lang??`es`,b=c.hydrateImport??`@elurjs/kit/island`,x=c.routerImport??`@elurjs/kit/router`,S=null,C={},w=`.`,T=null,E={name:`elur-kit`,enforce:`pre`,async configResolved(e){w=e.root;let c=(0,s.resolve)(w,_),l=await n.t((0,s.resolve)(w,h)),u=r.s(l,c,b,x);await(0,o.mkdir)((0,s.dirname)(c),{recursive:!0}),await(0,o.writeFile)(c,u,`utf8`);let d=(0,s.resolve)(w,m);S=await t.t(d),C=await i.n(d),a.s((0,s.resolve)(w,g)),T=await r.i(w)},configureServer(n){let o=u(n,w),E=d(()=>C,()=>S,o),D=(0,s.resolve)(w,m);l(n,D,(0,s.resolve)(w,h),(0,s.resolve)(w,g),w,_,b,x,()=>{S=null,C={},a.t()}),n.middlewares.use(async(a,s,l)=>{let u=new URL(a.url??`/`,`http://${a.headers.host??`localhost`}`),d=u.pathname;if(d===`/__elur-js/actions`&&a.method===`POST`){try{let t=await f(a),n=e.t(a,t),r=await e.n(n,E,c.actionSecurity);s.writeHead(r.status,Object.fromEntries(r.headers.entries())),s.end(await r.text())}catch(e){console.error(`[elur-kit] action error:`,e),s.writeHead(500,{"Content-Type":`text/plain; charset=utf-8`}),s.end(String(e))}return}if(d.startsWith(`/_elur/entry-client.js`)){let e=await n.transformRequest(`/.elur/entry-client.ts`);if(e){s.writeHead(200,{"Content-Type":`application/javascript; charset=utf-8`,"Cache-Control":`no-store, must-revalidate`}),s.end(e.code);return}}let m=S??=await t.t(D),h=Object.keys(C).length?C:C=await i.n(D);if(d===`/__elur-js/render`){let{renderPageBody:t,RouteNotFoundError:n}=await Promise.resolve().then(()=>require("../stream-DmZjYqHm.cjs")).then(e=>e.i);try{let n=u.searchParams.get(`page`)??`/`,r=u.searchParams.get(`search`)??``,c=(a.headers.accept??``).includes(`application/json`),l=e.t(a),{body:d,title:f,head:p,clearActionErrorCookie:g}=await t({routes:m,pathname:n,searchParams:new URLSearchParams(r),config:{lang:y,clientEntry:v},actions:i.t(h),importer:o,request:l});if(c){let e={"Content-Type":`application/json; charset=utf-8`};g&&(e[`X-Elur-Action-Clear-Cookie`]=g),s.writeHead(200,e),s.end(JSON.stringify({title:f,body:d,head:p,clearActionErrorCookie:g}))}else{let e={"Content-Type":`text/html; charset=utf-8`};g&&(e[`Set-Cookie`]=g),s.writeHead(200,e),s.end(d)}return}catch(e){if(e instanceof n){s.writeHead(404,{"Content-Type":`text/plain; charset=utf-8`}),s.end(`Not Found`);return}console.error(`[elur-kit] render endpoint error:`,e),s.writeHead(500,{"Content-Type":`text/plain; charset=utf-8`}),s.end(String(e));return}}if(!d.startsWith(`/@`)&&!d.startsWith(`/node_modules/`)&&!d.includes(`.`)){let t=e.a(d,m.api);if(t){try{let n=(await o(t.route.routePath))[a.method??`GET`];if(typeof n!=`function`){s.writeHead(405,{"Content-Type":`text/plain`}),s.end(`Method not allowed: ${a.method}`);return}let r=a.method&&a.method!==`GET`&&a.method!==`HEAD`?await f(a):void 0,i=await n(e.t(a,r),{params:t.params});s.writeHead(i.status,Object.fromEntries(i.headers.entries())),s.end(Buffer.from(await i.arrayBuffer()))}catch(e){console.error(`[elur-kit] API route error:`,e),s.writeHead(500,{"Content-Type":`text/plain; charset=utf-8`}),s.end(String(e))}return}}let g;if(T&&r.a(d,T.config)){let t=await r.o(T,e.t(a));if(t.kind===`response`){s.writeHead(t.response.status,Object.fromEntries(t.response.headers.entries())),s.end(Buffer.from(await t.response.arrayBuffer()));return}g=t.headers}await p(a,s,l,{routes:m,actions:h,clientEntry:v,lang:y,ssrLoad:o,middlewareHeaders:g})||l()})}};return r.r(c.interpolation??`auto`)?[E,r.n({appDir:m,islandsDir:h})]:[E]}function l(e,t,i,a,c,l,u,d,f){let p=e=>e.startsWith(t)||e.startsWith(i)||e.startsWith(a);async function m(){let t=await n.t(i),a=(0,s.resolve)(c,l),f=r.s(t,a,u,d);await(0,o.mkdir)((0,s.dirname)(a),{recursive:!0}),await(0,o.writeFile)(a,f,`utf8`);let p=e.moduleGraph.getModuleById(a);p&&e.moduleGraph.invalidateModule(p)}e.watcher.on(`change`,async t=>{if(!p(t))return;f();let n=e.moduleGraph.getModuleById(t);n&&e.moduleGraph.invalidateModule(n),t.startsWith(i)?(await m(),console.log(`[elur-kit] HMR reload islands after change:`,t)):t.startsWith(a)&&t.endsWith(`.md`)?console.log(`[elur-kit] HMR content changed:`,t):(t.includes(`.action.ts`)||t.includes(`.data.ts`)||t.includes(`page.ts`)||t.includes(`layout.ts`))&&console.log(`[elur-kit] HMR reload routes/actions after change:`,t)}),e.watcher.on(`add`,async e=>{p(e)&&(f(),e.startsWith(i)&&await m(),console.log(`[elur-kit] HMR new file detected:`,e))}),e.watcher.on(`unlink`,async t=>{if(!p(t))return;f();let n=e.moduleGraph.getModuleById(t);n&&e.moduleGraph.invalidateModule(n),t.startsWith(i)&&await m(),console.log(`[elur-kit] HMR file removed:`,t)})}function u(e,t){return n=>{let r=`/`+(0,s.relative)(t,n).split(`\\`).join(`/`);return e.ssrLoadModule(r)}}function d(t,n,r){return async(i,a)=>{let o=t(),s=n(),c;a&&s&&(c=s.pages.some(e=>e.path===a)?a:e.o(a,s.pages)?.route.path??a);let l=c?o[c]:Object.values(o).find(e=>e[i])??void 0,u=l?l[i]:void 0;if(!u)return;let d=(await r(u))[i];if(typeof d==`function`)return d}}function f(e){return new Promise((t,n)=>{let r=``;e.setEncoding(`utf8`),e.on(`data`,e=>{r+=e}),e.on(`end`,()=>t(r)),e.on(`error`,n)})}async function p(t,n,r,a){if(!a.routes)return!1;let o=i.t(a.actions),s=t.url??`/`;if(s.includes(`?`)&&(s=s.split(`?`)[0]),s.startsWith(`/@`)||s.startsWith(`/node_modules/`)||s.includes(`.`))return!1;let c={lang:a.lang,clientEntry:a.clientEntry},l=e.o(s,a.routes.pages);if(l)try{let r=e.t(t);if(a.middlewareHeaders)for(let[e,t]of Object.entries(a.middlewareHeaders))r.headers.set(e,t);let{html:i,clearActionErrorCookie:s}=await e.l({route:l.route,params:l.params,searchParams:new URLSearchParams(t.url?.split(`?`)[1]??``),config:c,importer:a.ssrLoad,actions:o,request:r}),u={"Content-Type":`text/html; charset=utf-8`,"Cache-Control":`no-store, must-revalidate`};return s&&(u[`Set-Cookie`]=s),n.writeHead(200,u),n.end(i),!0}catch(t){console.error(`[elur-kit] SSR render error:`,t);let r=await e.c({routes:a.routes,status:500,error:t,config:c,actions:o,importer:a.ssrLoad});return r?(n.writeHead(r.status,{"Content-Type":`text/html; charset=utf-8`,"Cache-Control":`no-store, must-revalidate`}),n.end(r.html)):(n.writeHead(500,{"Content-Type":`text/plain; charset=utf-8`,"Cache-Control":`no-store, must-revalidate`}),n.end(String(t))),!0}let u=await e.c({routes:a.routes,status:404,config:c,actions:o,importer:a.ssrLoad});return u?(n.writeHead(u.status,{"Content-Type":`text/html; charset=utf-8`,"Cache-Control":`no-store, must-revalidate`}),n.end(u.html),!0):!1}exports.coreSupportsPartialInterpolation=r.t,exports.elurJsInterpolationPlugin=r.n,exports.elurJsKit=c,exports.shouldUseLegacyInterpolation=r.r;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../node-http-Uct7DhmN.cjs"),t=require("../route-scanner-JY6YrNH5.cjs"),n=require("../scan-CY2O9ty6.cjs"),r=require("../interpolation-plugin-C0dTd69H.cjs"),i=require("../scan-DXzYtmRQ.cjs"),a=require("../collections-VDy5g9p8.cjs");let o=require("node:fs/promises"),s=require("node:path");function c(c={}){let m=c.appDir??`src/app`,h=c.islandsDir??`src/islands`,g=c.contentDir??`src/content`,_=c.generatedEntry??`.elur/entry-client.ts`,v=c.clientEntry??`/_elur/entry-client.js`,y=c.lang??`es`,b=c.hydrateImport??`@elurjs/kit/island`,x=c.routerImport??`@elurjs/kit/router`,S=null,C={},w=`.`,T=null,E={name:`elur-kit`,enforce:`pre`,async configResolved(l){w=l.root;let u=(0,s.resolve)(w,_),d=await n.t((0,s.resolve)(w,h)),f=r.i(d,u,b,x,c.router);await(0,o.mkdir)((0,s.dirname)(u),{recursive:!0}),await(0,o.writeFile)(u,f,`utf8`);let p=(0,s.resolve)(w,m);S=await t.t(p),C=await i.n(p),a.s((0,s.resolve)(w,g)),T=await e.r(w)},configureServer(n){let r=u(n,w),o=d(()=>C,()=>S,r),E=(0,s.resolve)(w,m);l(n,E,(0,s.resolve)(w,h),(0,s.resolve)(w,g),w,_,b,x,c.router,()=>{S=null,C={},a.t()}),n.middlewares.use(async(a,s,l)=>{let u=new URL(a.url??`/`,`http://${a.headers.host??`localhost`}`),d=u.pathname;if(d===`/__elur-js/actions`&&a.method===`POST`){try{let t=await f(a),n=e.t(a,t),r=await e.o(n,o,c.actionSecurity);s.writeHead(r.status,Object.fromEntries(r.headers.entries())),s.end(await r.text())}catch(e){console.error(`[elur-kit] action error:`,e),s.writeHead(500,{"Content-Type":`text/plain; charset=utf-8`}),s.end(String(e))}return}if(d.startsWith(`/_elur/entry-client.js`)){let e=await n.transformRequest(`/.elur/entry-client.ts`);if(e){s.writeHead(200,{"Content-Type":`application/javascript; charset=utf-8`,"Cache-Control":`no-store, must-revalidate`}),s.end(e.code);return}}let m=S??=await t.t(E),h=Object.keys(C).length?C:C=await i.n(E);if(d===`/__elur-js/render`){let{renderPageBody:t,RouteNotFoundError:n}=await Promise.resolve().then(()=>require("../stream-Cg-xYG82.cjs")).then(e=>e.i);try{let n=u.searchParams.get(`page`)??`/`,o=u.searchParams.get(`search`)??``,c=(a.headers.accept??``).includes(`application/json`),l=e.t(a),d=await t({routes:m,pathname:n,searchParams:new URLSearchParams(o),config:{lang:y,clientEntry:v},actions:i.t(h),importer:r,request:l});if(d.response){s.writeHead(d.response.status,Object.fromEntries(d.response.headers.entries())),s.end(Buffer.from(await d.response.arrayBuffer()));return}let{body:f,title:p,head:g,clearActionErrorCookie:_,data:b,actions:x}=d;if(c){let e={"Content-Type":`application/json; charset=utf-8`};_&&(e[`X-Elur-Action-Clear-Cookie`]=_),s.writeHead(200,e),s.end(JSON.stringify({title:p,body:f,head:g??null,data:b??null,actions:x??null,clearActionErrorCookie:_??null}))}else{let e={"Content-Type":`text/html; charset=utf-8`};_&&(e[`Set-Cookie`]=_),s.writeHead(200,e),s.end(f)}return}catch(e){if(e instanceof n){s.writeHead(404,{"Content-Type":`text/plain; charset=utf-8`}),s.end(`Not Found`);return}console.error(`[elur-kit] render endpoint error:`,e),s.writeHead(500,{"Content-Type":`text/plain; charset=utf-8`}),s.end(String(e));return}}if(!d.startsWith(`/@`)&&!d.startsWith(`/node_modules/`)&&!d.includes(`.`)){let t=e.l(d,m.api);if(t){try{let n=(await r(t.route.routePath))[a.method??`GET`];if(typeof n!=`function`){s.writeHead(405,{"Content-Type":`text/plain`}),s.end(`Method not allowed: ${a.method}`);return}let i=a.method&&a.method!==`GET`&&a.method!==`HEAD`?await f(a):void 0,o=await n(e.t(a,i),{params:t.params});s.writeHead(o.status,Object.fromEntries(o.headers.entries())),s.end(Buffer.from(await o.arrayBuffer()))}catch(e){console.error(`[elur-kit] API route error:`,e),s.writeHead(500,{"Content-Type":`text/plain; charset=utf-8`}),s.end(String(e))}return}}let g;if(T&&e.i(d,T.config)){let t=await e.a(T,e.t(a));if(t.kind===`response`){s.writeHead(t.response.status,Object.fromEntries(t.response.headers.entries())),s.end(Buffer.from(await t.response.arrayBuffer()));return}g=t.headers}await p(a,s,l,{routes:m,actions:h,clientEntry:v,lang:y,ssrLoad:r,middlewareHeaders:g})||l()})}};return r.r(c.interpolation??`auto`)?[E,r.n({appDir:m,islandsDir:h})]:[E]}function l(e,t,i,a,c,l,u,d,f,p){let m=e=>e.startsWith(t)||e.startsWith(i)||e.startsWith(a);async function h(){let t=await n.t(i),a=(0,s.resolve)(c,l),p=r.i(t,a,u,d,f);await(0,o.mkdir)((0,s.dirname)(a),{recursive:!0}),await(0,o.writeFile)(a,p,`utf8`);let m=e.moduleGraph.getModuleById(a);m&&e.moduleGraph.invalidateModule(m)}e.watcher.on(`change`,async t=>{if(!m(t))return;p();let n=e.moduleGraph.getModuleById(t);n&&e.moduleGraph.invalidateModule(n),t.startsWith(i)?(await h(),console.log(`[elur-kit] HMR reload islands after change:`,t)):t.startsWith(a)&&t.endsWith(`.md`)?console.log(`[elur-kit] HMR content changed:`,t):(t.includes(`.action.ts`)||t.includes(`.data.ts`)||t.includes(`page.ts`)||t.includes(`layout.ts`))&&console.log(`[elur-kit] HMR reload routes/actions after change:`,t)}),e.watcher.on(`add`,async e=>{m(e)&&(p(),e.startsWith(i)&&await h(),console.log(`[elur-kit] HMR new file detected:`,e))}),e.watcher.on(`unlink`,async t=>{if(!m(t))return;p();let n=e.moduleGraph.getModuleById(t);n&&e.moduleGraph.invalidateModule(n),t.startsWith(i)&&await h(),console.log(`[elur-kit] HMR file removed:`,t)})}function u(e,t){return n=>{let r=`/`+(0,s.relative)(t,n).split(`\\`).join(`/`);return e.ssrLoadModule(r)}}function d(t,n,r){return async(i,a)=>{let o=t(),s=n(),c;a&&s&&(c=s.pages.some(e=>e.path===a)?a:e.u(a,s.pages)?.route.path??a);let l=c?o[c]:Object.values(o).find(e=>e[i])??void 0,u=l?l[i]:void 0;if(!u)return;let d=(await r(u))[i];if(typeof d==`function`)return d}}function f(e){return new Promise((t,n)=>{let r=``;e.setEncoding(`utf8`),e.on(`data`,e=>{r+=e}),e.on(`end`,()=>t(r)),e.on(`error`,n)})}async function p(t,n,r,a){if(!a.routes)return!1;let o=i.t(a.actions),s=t.url??`/`;if(s.includes(`?`)&&(s=s.split(`?`)[0]),s.startsWith(`/@`)||s.startsWith(`/node_modules/`)||s.includes(`.`))return!1;let c={lang:a.lang,clientEntry:a.clientEntry},l=e.u(s,a.routes.pages);if(l)try{let r=e.t(t);if(a.middlewareHeaders)for(let[e,t]of Object.entries(a.middlewareHeaders))r.headers.set(e,t);let{html:i,clearActionErrorCookie:s}=await e.p({route:l.route,params:l.params,searchParams:new URLSearchParams(t.url?.split(`?`)[1]??``),config:c,importer:a.ssrLoad,actions:o,request:r}),u={"Content-Type":`text/html; charset=utf-8`,"Cache-Control":`no-store, must-revalidate`};return s&&(u[`Set-Cookie`]=s),n.writeHead(200,u),n.end(i),!0}catch(t){console.error(`[elur-kit] SSR render error:`,t);let r=await e.f({routes:a.routes,status:500,error:t,config:c,actions:o,importer:a.ssrLoad});return r?(n.writeHead(r.status,{"Content-Type":`text/html; charset=utf-8`,"Cache-Control":`no-store, must-revalidate`}),n.end(r.html)):(n.writeHead(500,{"Content-Type":`text/plain; charset=utf-8`,"Cache-Control":`no-store, must-revalidate`}),n.end(String(t))),!0}let u=await e.f({routes:a.routes,status:404,config:c,actions:o,importer:a.ssrLoad});return u?(n.writeHead(u.status,{"Content-Type":`text/html; charset=utf-8`,"Cache-Control":`no-store, must-revalidate`}),n.end(u.html),!0):!1}exports.coreSupportsPartialInterpolation=r.t,exports.elurJsInterpolationPlugin=r.n,exports.elurJsKit=c,exports.shouldUseLegacyInterpolation=r.r;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/vite/index.ts"],"sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, relative, resolve } from \"node:path\";\nimport type { Plugin, Connect, ViteDevServer } from \"vite\";\nimport { scanRoutes } from \"../router/route-scanner.js\";\nimport { scanActions, actionNames, type ActionRegistry } from \"../action/scan.js\";\nimport { handleActionRequest, type ActionSecurityOptions } from \"../action/server.js\";\nimport { scanIslands } from \"../island/scan.js\";\nimport { buildEntrySource } from \"../island/generate-entry.js\";\nimport { matchApiRoute, matchRoute } from \"../ssr/match.js\";\nimport { renderPage, renderErrorPage } from \"../ssr/render.js\";\nimport { setContentRoot, clearContentCache } from \"../content/collections.js\";\nimport { loadMiddleware, matchesMiddleware, runMiddleware, type LoadedMiddleware } from \"../middleware/index.js\";\nimport { elurJsInterpolationPlugin, shouldUseLegacyInterpolation, type InterpolationMode } from \"./interpolation-plugin.js\";\nimport { incomingMessageToRequest } from \"../runtime/node-http.js\";\n\nexport interface ElurJsKitViteOptions {\n /** App directory relative to Vite root (default: src/app). */\n appDir?: string;\n /** Islands directory relative to Vite root (default: src/islands). */\n islandsDir?: string;\n /** Content directory relative to Vite root (default: src/content). */\n contentDir?: string;\n /** Where to write the generated client entry (default: .elur/entry-client.ts). */\n generatedEntry?: string;\n /** Public path for the client entry module (default: /_elur/entry-client.js). */\n clientEntry?: string;\n /** HTML lang attribute (default: es). */\n lang?: string;\n /** Import specifier for hydrateIslands in the generated entry. */\n hydrateImport?: string;\n /** Import specifier for startClientRouter in the generated entry. */\n routerImport?: string;\n /** CSRF / origin policy applied to the server actions endpoint in dev. */\n actionSecurity?: ActionSecurityOptions;\n /**\n * How the legacy interpolation transform is handled (default: \"auto\").\n * With a Elur core that supports partial attribute interpolation natively\n * the transform is not applied; use \"legacy\" for migrations against older\n * cores and \"off\" to never transform.\n */\n interpolation?: InterpolationMode;\n}\n\n/**\n * Official Vite plugin for elur-kit.\n *\n * In dev mode it generates the islands entry and renders every page via SSR.\n * In production builds it can be combined with `elur-kit build` to generate\n * static HTML files.\n */\nexport function elurJsKit(options: ElurJsKitViteOptions = {}): Plugin[] {\n const appDir = options.appDir ?? \"src/app\";\n const islandsDir = options.islandsDir ?? \"src/islands\";\n const contentDir = options.contentDir ?? \"src/content\";\n const generatedEntry = options.generatedEntry ?? \".elur/entry-client.ts\";\n const clientEntry = options.clientEntry ?? \"/_elur/entry-client.js\";\n const lang = options.lang ?? \"es\";\n const hydrateImport = options.hydrateImport ?? \"@elurjs/kit/island\";\n const routerImport = options.routerImport ?? \"@elurjs/kit/router\";\n\n let routes: Awaited<ReturnType<typeof scanRoutes>> | null = null;\n let actions: ActionRegistry = {};\n let root: string = \".\";\n let middleware: LoadedMiddleware | null = null;\n\n const mainPlugin: Plugin = {\n name: \"elur-kit\",\n enforce: \"pre\",\n\n async configResolved(config) {\n root = config.root;\n const entryPath = resolve(root, generatedEntry);\n const islands = await scanIslands(resolve(root, islandsDir));\n const source = buildEntrySource(islands, entryPath, hydrateImport, routerImport);\n await mkdir(dirname(entryPath), { recursive: true });\n await writeFile(entryPath, source, \"utf8\");\n\n const appDirPath = resolve(root, appDir);\n routes = await scanRoutes(appDirPath);\n actions = await scanActions(appDirPath);\n\n // Wire up the content layer root so getCollection/getEntry resolve\n // from the user's src/content directory.\n setContentRoot(resolve(root, contentDir));\n\n // Load user middleware (src/middleware.ts) if it exists.\n middleware = await loadMiddleware(root);\n },\n\n configureServer(server) {\n const ssrLoad = createSsrLoader(server, root);\n const resolveAction = createActionResolver(() => actions, () => routes, ssrLoad);\n\n const appDirPath = resolve(root, appDir);\n const islandsDirPath = resolve(root, islandsDir);\n const contentDirPath = resolve(root, contentDir);\n setupHmr(server, appDirPath, islandsDirPath, contentDirPath, root, generatedEntry, hydrateImport, routerImport, () => {\n routes = null;\n actions = {};\n clearContentCache();\n });\n\n server.middlewares.use(async (req, res, next) => {\n const requestUrl = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const urlPath = requestUrl.pathname;\n\n // Server actions endpoint.\n if (urlPath === \"/__elur-js/actions\" && req.method === \"POST\") {\n try {\n const body = await readRequestBody(req);\n const request = incomingMessageToRequest(req, body);\n const response = await handleActionRequest(request, resolveAction, options.actionSecurity);\n res.writeHead(response.status, Object.fromEntries(response.headers.entries()));\n res.end(await response.text());\n } catch (err) {\n console.error(\"[elur-kit] action error:\", err);\n res.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n res.end(String(err));\n }\n return;\n }\n\n if (urlPath.startsWith(\"/_elur/entry-client.js\")) {\n const transformed = await server.transformRequest(\n \"/.elur/entry-client.ts\",\n );\n if (transformed) {\n res.writeHead(200, {\n \"Content-Type\": \"application/javascript; charset=utf-8\",\n \"Cache-Control\": \"no-store, must-revalidate\",\n });\n res.end(transformed.code);\n return;\n }\n }\n\n const currentRoutes = routes ?? (routes = await scanRoutes(appDirPath));\n const currentActions = Object.keys(actions).length ? actions : (actions = await scanActions(appDirPath));\n\n // Render endpoint used by the SPA router and streaming boundaries.\n if (urlPath === \"/__elur-js/render\") {\n const { renderPageBody, RouteNotFoundError } = await import(\"../ssr/stream.js\");\n try {\n const page = requestUrl.searchParams.get(\"page\") ?? \"/\";\n const search = requestUrl.searchParams.get(\"search\") ?? \"\";\n const wantsJson = (req.headers[\"accept\"] ?? \"\").includes(\"application/json\");\n const request = incomingMessageToRequest(req);\n const { body, title, head, clearActionErrorCookie } = await renderPageBody({\n routes: currentRoutes,\n pathname: page,\n searchParams: new URLSearchParams(search),\n config: { lang, clientEntry },\n actions: actionNames(currentActions),\n importer: ssrLoad,\n request,\n });\n if (wantsJson) {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json; charset=utf-8\" };\n if (clearActionErrorCookie) headers[\"X-Elur-Action-Clear-Cookie\"] = clearActionErrorCookie;\n res.writeHead(200, headers);\n res.end(JSON.stringify({ title, body, head, clearActionErrorCookie }));\n } else {\n const headers: Record<string, string> = { \"Content-Type\": \"text/html; charset=utf-8\" };\n if (clearActionErrorCookie) headers[\"Set-Cookie\"] = clearActionErrorCookie;\n res.writeHead(200, headers);\n res.end(body);\n }\n return;\n } catch (err) {\n if (err instanceof RouteNotFoundError) {\n res.writeHead(404, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n res.end(\"Not Found\");\n return;\n }\n console.error(\"[elur-kit] render endpoint error:\", err);\n res.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n res.end(String(err));\n return;\n }\n }\n\n if (!urlPath.startsWith(\"/@\") && !urlPath.startsWith(\"/node_modules/\") && !urlPath.includes(\".\")) {\n const apiMatch = matchApiRoute(urlPath, currentRoutes.api);\n if (apiMatch) {\n try {\n const mod = (await ssrLoad(apiMatch.route.routePath)) as Record<\n string,\n (request: Request, context?: { params: Record<string, string | string[]> }) => unknown\n >;\n const handler = mod[req.method ?? \"GET\"];\n if (typeof handler !== \"function\") {\n res.writeHead(405, { \"Content-Type\": \"text/plain\" });\n res.end(`Method not allowed: ${req.method}`);\n return;\n }\n const body = req.method && req.method !== \"GET\" && req.method !== \"HEAD\" ? await readRequestBody(req) : undefined;\n const request = incomingMessageToRequest(req, body);\n const response = (await handler(request, { params: apiMatch.params })) as Response;\n res.writeHead(response.status, Object.fromEntries(response.headers.entries()));\n res.end(Buffer.from(await response.arrayBuffer()));\n } catch (err) {\n console.error(\"[elur-kit] API route error:\", err);\n res.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n res.end(String(err));\n }\n return;\n }\n }\n\n // Run middleware before SSR rendering.\n let middlewareHeaders: Record<string, string> | undefined;\n if (middleware && matchesMiddleware(urlPath, middleware.config)) {\n const mwResult = await runMiddleware(middleware, incomingMessageToRequest(req));\n if (mwResult.kind === \"response\") {\n res.writeHead(mwResult.response.status, Object.fromEntries(mwResult.response.headers.entries()));\n res.end(Buffer.from(await mwResult.response.arrayBuffer()));\n return;\n }\n middlewareHeaders = mwResult.headers;\n }\n\n const handled = await handleSsrRequest(req, res, next, {\n routes: currentRoutes,\n actions: currentActions,\n clientEntry,\n lang,\n ssrLoad,\n middlewareHeaders,\n });\n if (!handled) next();\n });\n },\n };\n\n return shouldUseLegacyInterpolation(options.interpolation ?? \"auto\")\n ? [mainPlugin, elurJsInterpolationPlugin({ appDir, islandsDir })]\n : [mainPlugin];\n}\n\nexport { elurJsInterpolationPlugin, type InterpolationPluginOptions } from \"./interpolation-plugin.js\";\nexport type { InterpolationMode } from \"./interpolation-plugin.js\";\nexport { coreSupportsPartialInterpolation, shouldUseLegacyInterpolation } from \"./interpolation-plugin.js\";\n\nfunction setupHmr(\n server: ViteDevServer,\n appDirPath: string,\n islandsDirPath: string,\n contentDirPath: string,\n root: string,\n generatedEntry: string,\n hydrateImport: string,\n routerImport: string,\n invalidate: () => void,\n) {\n const isRelevant = (path: string) =>\n path.startsWith(appDirPath) || path.startsWith(islandsDirPath) || path.startsWith(contentDirPath);\n\n async function regenerateIslandEntry() {\n const islands = await scanIslands(islandsDirPath);\n const entryPath = resolve(root, generatedEntry);\n const source = buildEntrySource(islands, entryPath, hydrateImport, routerImport);\n await mkdir(dirname(entryPath), { recursive: true });\n await writeFile(entryPath, source, \"utf8\");\n const entryMod = server.moduleGraph.getModuleById(entryPath);\n if (entryMod) server.moduleGraph.invalidateModule(entryMod);\n }\n\n server.watcher.on(\"change\", async (path) => {\n if (!isRelevant(path)) return;\n invalidate();\n const mod = server.moduleGraph.getModuleById(path);\n if (mod) server.moduleGraph.invalidateModule(mod);\n if (path.startsWith(islandsDirPath)) {\n await regenerateIslandEntry();\n console.log(\"[elur-kit] HMR reload islands after change:\", path);\n } else if (path.startsWith(contentDirPath) && path.endsWith(\".md\")) {\n console.log(\"[elur-kit] HMR content changed:\", path);\n } else if (path.includes(\".action.ts\") || path.includes(\".data.ts\") || path.includes(\"page.ts\") || path.includes(\"layout.ts\")) {\n console.log(\"[elur-kit] HMR reload routes/actions after change:\", path);\n }\n });\n\n server.watcher.on(\"add\", async (path) => {\n if (!isRelevant(path)) return;\n invalidate();\n if (path.startsWith(islandsDirPath)) {\n await regenerateIslandEntry();\n }\n console.log(\"[elur-kit] HMR new file detected:\", path);\n });\n\n server.watcher.on(\"unlink\", async (path) => {\n if (!isRelevant(path)) return;\n invalidate();\n const mod = server.moduleGraph.getModuleById(path);\n if (mod) server.moduleGraph.invalidateModule(mod);\n if (path.startsWith(islandsDirPath)) {\n await regenerateIslandEntry();\n }\n console.log(\"[elur-kit] HMR file removed:\", path);\n });\n}\n\nfunction createSsrLoader(server: ViteDevServer, root: string) {\n return (filePath: string) => {\n const rel = relative(root, filePath);\n const url = \"/\" + rel.split(\"\\\\\").join(\"/\");\n return server.ssrLoadModule(url);\n };\n}\n\nfunction createActionResolver(\n getActions: () => import(\"../action/scan.js\").ActionRegistry,\n getRoutes: () => Awaited<ReturnType<typeof scanRoutes>> | null,\n ssrLoad: (path: string) => Promise<unknown>,\n) {\n return async (name: string, page?: string) => {\n const actions = getActions();\n const routes = getRoutes();\n let pageKey: string | undefined;\n if (page && routes) {\n pageKey = routes.pages.some((route) => route.path === page)\n ? page\n : (matchRoute(page, routes.pages)?.route.path ?? page);\n }\n const pageActions = pageKey ? actions[pageKey] : Object.values(actions).find((p) => p[name]) ?? undefined;\n const actionPath = pageActions ? pageActions[name] : undefined;\n if (!actionPath) return undefined;\n const mod = (await ssrLoad(actionPath)) as Record<string, unknown>;\n const action = mod[name];\n if (typeof action === \"function\") {\n return action as (...args: unknown[]) => unknown;\n }\n return undefined;\n };\n}\n\nfunction readRequestBody(req: Connect.IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n let body = \"\";\n req.setEncoding(\"utf8\");\n req.on(\"data\", (chunk) => {\n body += chunk;\n });\n req.on(\"end\", () => resolve(body));\n req.on(\"error\", reject);\n });\n}\n\ninterface SsrHandlerOptions {\n routes: Awaited<ReturnType<typeof scanRoutes>> | null;\n actions: ActionRegistry;\n clientEntry: string;\n lang: string;\n ssrLoad: (path: string) => Promise<unknown>;\n middlewareHeaders?: Record<string, string>;\n}\n\nasync function handleSsrRequest(\n req: Connect.IncomingMessage,\n res: import(\"node:http\").ServerResponse,\n _next: Connect.NextFunction,\n options: SsrHandlerOptions,\n): Promise<boolean> {\n if (!options.routes) return false;\n const publicActions = actionNames(options.actions);\n\n let urlPath = req.url ?? \"/\";\n if (urlPath.includes(\"?\")) urlPath = urlPath.split(\"?\")[0];\n\n // Let Vite handle its own internals and assets.\n if (urlPath.startsWith(\"/@\") || urlPath.startsWith(\"/node_modules/\")) {\n return false;\n }\n\n // Skip explicit file requests.\n if (urlPath.includes(\".\")) return false;\n\n const config = { lang: options.lang, clientEntry: options.clientEntry };\n const match = matchRoute(urlPath, options.routes.pages);\n if (match) {\n try {\n const request = incomingMessageToRequest(req);\n if (options.middlewareHeaders) {\n for (const [name, value] of Object.entries(options.middlewareHeaders)) request.headers.set(name, value);\n }\n const { html, clearActionErrorCookie } = await renderPage({\n route: match.route,\n params: match.params,\n searchParams: new URLSearchParams(req.url?.split(\"?\")[1] ?? \"\"),\n config,\n importer: options.ssrLoad,\n actions: publicActions,\n request,\n });\n const responseHeaders: Record<string, string> = {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store, must-revalidate\",\n };\n if (clearActionErrorCookie) responseHeaders[\"Set-Cookie\"] = clearActionErrorCookie;\n res.writeHead(200, responseHeaders);\n res.end(html);\n return true;\n } catch (err) {\n console.error(\"[elur-kit] SSR render error:\", err);\n const errorResult = await renderErrorPage({\n routes: options.routes,\n status: 500,\n error: err,\n config,\n actions: publicActions,\n importer: options.ssrLoad,\n });\n if (errorResult) {\n res.writeHead(errorResult.status, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store, must-revalidate\",\n });\n res.end(errorResult.html);\n } else {\n res.writeHead(500, {\n \"Content-Type\": \"text/plain; charset=utf-8\",\n \"Cache-Control\": \"no-store, must-revalidate\",\n });\n res.end(String(err));\n }\n return true;\n }\n }\n\n const errorResult = await renderErrorPage({\n routes: options.routes,\n status: 404,\n config,\n actions: publicActions,\n importer: options.ssrLoad,\n });\n if (errorResult) {\n res.writeHead(errorResult.status, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store, must-revalidate\",\n });\n res.end(errorResult.html);\n return true;\n }\n\n return false;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/vite/index.ts"],"sourcesContent":["import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, relative, resolve } from \"node:path\";\nimport type { Plugin, Connect, ViteDevServer } from \"vite\";\nimport { scanRoutes } from \"../router/route-scanner.js\";\nimport { scanActions, actionNames, type ActionRegistry } from \"../action/scan.js\";\nimport { handleActionRequest, type ActionSecurityOptions } from \"../action/server.js\";\nimport { scanIslands } from \"../island/scan.js\";\nimport { buildEntrySource } from \"../island/generate-entry.js\";\nimport { matchApiRoute, matchRoute } from \"../ssr/match.js\";\nimport { renderPage, renderErrorPage } from \"../ssr/render.js\";\nimport { setContentRoot, clearContentCache } from \"../content/collections.js\";\nimport { loadMiddleware, matchesMiddleware, runMiddleware, type LoadedMiddleware } from \"../middleware/index.js\";\nimport { elurJsInterpolationPlugin, shouldUseLegacyInterpolation, type InterpolationMode } from \"./interpolation-plugin.js\";\nimport { incomingMessageToRequest } from \"../runtime/node-http.js\";\n\nexport interface ElurJsKitViteOptions {\n /** App directory relative to Vite root (default: src/app). */\n appDir?: string;\n /** Islands directory relative to Vite root (default: src/islands). */\n islandsDir?: string;\n /** Content directory relative to Vite root (default: src/content). */\n contentDir?: string;\n /** Where to write the generated client entry (default: .elur/entry-client.ts). */\n generatedEntry?: string;\n /** Public path for the client entry module (default: /_elur/entry-client.js). */\n clientEntry?: string;\n /** HTML lang attribute (default: es). */\n lang?: string;\n /** Import specifier for hydrateIslands in the generated entry. */\n hydrateImport?: string;\n /** Import specifier for startClientRouter in the generated entry. */\n routerImport?: string;\n /**\n * Client router flags baked into the generated dev entry. In dev the entry\n * is never gated (HMR needs it on every page), but `enabled`/`prefetch`\n * are honored so behavior matches production.\n */\n router?: {\n enabled?: boolean;\n prefetch?: boolean;\n morph?: boolean;\n loadingIndicator?: boolean;\n };\n /** CSRF / origin policy applied to the server actions endpoint in dev. */\n actionSecurity?: ActionSecurityOptions;\n /**\n * How the legacy interpolation transform is handled (default: \"auto\").\n * With a Elur core that supports partial attribute interpolation natively\n * the transform is not applied; use \"legacy\" for migrations against older\n * cores and \"off\" to never transform.\n */\n interpolation?: InterpolationMode;\n}\n\n/**\n * Official Vite plugin for elur-kit.\n *\n * In dev mode it generates the islands entry and renders every page via SSR.\n * In production builds it can be combined with `elur-kit build` to generate\n * static HTML files.\n */\nexport function elurJsKit(options: ElurJsKitViteOptions = {}): Plugin[] {\n const appDir = options.appDir ?? \"src/app\";\n const islandsDir = options.islandsDir ?? \"src/islands\";\n const contentDir = options.contentDir ?? \"src/content\";\n const generatedEntry = options.generatedEntry ?? \".elur/entry-client.ts\";\n const clientEntry = options.clientEntry ?? \"/_elur/entry-client.js\";\n const lang = options.lang ?? \"es\";\n const hydrateImport = options.hydrateImport ?? \"@elurjs/kit/island\";\n const routerImport = options.routerImport ?? \"@elurjs/kit/router\";\n\n let routes: Awaited<ReturnType<typeof scanRoutes>> | null = null;\n let actions: ActionRegistry = {};\n let root: string = \".\";\n let middleware: LoadedMiddleware | null = null;\n\n const mainPlugin: Plugin = {\n name: \"elur-kit\",\n enforce: \"pre\",\n\n async configResolved(config) {\n root = config.root;\n const entryPath = resolve(root, generatedEntry);\n const islands = await scanIslands(resolve(root, islandsDir));\n const source = buildEntrySource(islands, entryPath, hydrateImport, routerImport, options.router);\n await mkdir(dirname(entryPath), { recursive: true });\n await writeFile(entryPath, source, \"utf8\");\n\n const appDirPath = resolve(root, appDir);\n routes = await scanRoutes(appDirPath);\n actions = await scanActions(appDirPath);\n\n // Wire up the content layer root so getCollection/getEntry resolve\n // from the user's src/content directory.\n setContentRoot(resolve(root, contentDir));\n\n // Load user middleware (src/middleware.ts) if it exists.\n middleware = await loadMiddleware(root);\n },\n\n configureServer(server) {\n const ssrLoad = createSsrLoader(server, root);\n const resolveAction = createActionResolver(() => actions, () => routes, ssrLoad);\n\n const appDirPath = resolve(root, appDir);\n const islandsDirPath = resolve(root, islandsDir);\n const contentDirPath = resolve(root, contentDir);\n setupHmr(server, appDirPath, islandsDirPath, contentDirPath, root, generatedEntry, hydrateImport, routerImport, options.router, () => {\n routes = null;\n actions = {};\n clearContentCache();\n });\n\n server.middlewares.use(async (req, res, next) => {\n const requestUrl = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const urlPath = requestUrl.pathname;\n\n // Server actions endpoint.\n if (urlPath === \"/__elur-js/actions\" && req.method === \"POST\") {\n try {\n const body = await readRequestBody(req);\n const request = incomingMessageToRequest(req, body);\n const response = await handleActionRequest(request, resolveAction, options.actionSecurity);\n res.writeHead(response.status, Object.fromEntries(response.headers.entries()));\n res.end(await response.text());\n } catch (err) {\n console.error(\"[elur-kit] action error:\", err);\n res.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n res.end(String(err));\n }\n return;\n }\n\n if (urlPath.startsWith(\"/_elur/entry-client.js\")) {\n const transformed = await server.transformRequest(\n \"/.elur/entry-client.ts\",\n );\n if (transformed) {\n res.writeHead(200, {\n \"Content-Type\": \"application/javascript; charset=utf-8\",\n \"Cache-Control\": \"no-store, must-revalidate\",\n });\n res.end(transformed.code);\n return;\n }\n }\n\n const currentRoutes = routes ?? (routes = await scanRoutes(appDirPath));\n const currentActions = Object.keys(actions).length ? actions : (actions = await scanActions(appDirPath));\n\n // Render endpoint used by the SPA router and streaming boundaries.\n if (urlPath === \"/__elur-js/render\") {\n const { renderPageBody, RouteNotFoundError } = await import(\"../ssr/stream.js\");\n try {\n const page = requestUrl.searchParams.get(\"page\") ?? \"/\";\n const search = requestUrl.searchParams.get(\"search\") ?? \"\";\n const wantsJson = (req.headers[\"accept\"] ?? \"\").includes(\"application/json\");\n const request = incomingMessageToRequest(req);\n const result = await renderPageBody({\n routes: currentRoutes,\n pathname: page,\n searchParams: new URLSearchParams(search),\n config: { lang, clientEntry },\n actions: actionNames(currentActions),\n importer: ssrLoad,\n request,\n });\n if (result.response) {\n res.writeHead(result.response.status, Object.fromEntries(result.response.headers.entries()));\n res.end(Buffer.from(await result.response.arrayBuffer()));\n return;\n }\n const { body, title, head, clearActionErrorCookie, data, actions: actionsPayload } = result;\n if (wantsJson) {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json; charset=utf-8\" };\n if (clearActionErrorCookie) headers[\"X-Elur-Action-Clear-Cookie\"] = clearActionErrorCookie;\n res.writeHead(200, headers);\n res.end(JSON.stringify({\n title,\n body,\n head: head ?? null,\n data: data ?? null,\n actions: actionsPayload ?? null,\n clearActionErrorCookie: clearActionErrorCookie ?? null,\n }));\n } else {\n const headers: Record<string, string> = { \"Content-Type\": \"text/html; charset=utf-8\" };\n if (clearActionErrorCookie) headers[\"Set-Cookie\"] = clearActionErrorCookie;\n res.writeHead(200, headers);\n res.end(body);\n }\n return;\n } catch (err) {\n if (err instanceof RouteNotFoundError) {\n res.writeHead(404, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n res.end(\"Not Found\");\n return;\n }\n console.error(\"[elur-kit] render endpoint error:\", err);\n res.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n res.end(String(err));\n return;\n }\n }\n\n if (!urlPath.startsWith(\"/@\") && !urlPath.startsWith(\"/node_modules/\") && !urlPath.includes(\".\")) {\n const apiMatch = matchApiRoute(urlPath, currentRoutes.api);\n if (apiMatch) {\n try {\n const mod = (await ssrLoad(apiMatch.route.routePath)) as Record<\n string,\n (request: Request, context?: { params: Record<string, string | string[]> }) => unknown\n >;\n const handler = mod[req.method ?? \"GET\"];\n if (typeof handler !== \"function\") {\n res.writeHead(405, { \"Content-Type\": \"text/plain\" });\n res.end(`Method not allowed: ${req.method}`);\n return;\n }\n const body = req.method && req.method !== \"GET\" && req.method !== \"HEAD\" ? await readRequestBody(req) : undefined;\n const request = incomingMessageToRequest(req, body);\n const response = (await handler(request, { params: apiMatch.params })) as Response;\n res.writeHead(response.status, Object.fromEntries(response.headers.entries()));\n res.end(Buffer.from(await response.arrayBuffer()));\n } catch (err) {\n console.error(\"[elur-kit] API route error:\", err);\n res.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n res.end(String(err));\n }\n return;\n }\n }\n\n // Run middleware before SSR rendering.\n let middlewareHeaders: Record<string, string> | undefined;\n if (middleware && matchesMiddleware(urlPath, middleware.config)) {\n const mwResult = await runMiddleware(middleware, incomingMessageToRequest(req));\n if (mwResult.kind === \"response\") {\n res.writeHead(mwResult.response.status, Object.fromEntries(mwResult.response.headers.entries()));\n res.end(Buffer.from(await mwResult.response.arrayBuffer()));\n return;\n }\n middlewareHeaders = mwResult.headers;\n }\n\n const handled = await handleSsrRequest(req, res, next, {\n routes: currentRoutes,\n actions: currentActions,\n clientEntry,\n lang,\n ssrLoad,\n middlewareHeaders,\n });\n if (!handled) next();\n });\n },\n };\n\n return shouldUseLegacyInterpolation(options.interpolation ?? \"auto\")\n ? [mainPlugin, elurJsInterpolationPlugin({ appDir, islandsDir })]\n : [mainPlugin];\n}\n\nexport { elurJsInterpolationPlugin, type InterpolationPluginOptions } from \"./interpolation-plugin.js\";\nexport type { InterpolationMode } from \"./interpolation-plugin.js\";\nexport { coreSupportsPartialInterpolation, shouldUseLegacyInterpolation } from \"./interpolation-plugin.js\";\n\nfunction setupHmr(\n server: ViteDevServer,\n appDirPath: string,\n islandsDirPath: string,\n contentDirPath: string,\n root: string,\n generatedEntry: string,\n hydrateImport: string,\n routerImport: string,\n routerOptions: ElurJsKitViteOptions[\"router\"],\n invalidate: () => void,\n) {\n const isRelevant = (path: string) =>\n path.startsWith(appDirPath) || path.startsWith(islandsDirPath) || path.startsWith(contentDirPath);\n\n async function regenerateIslandEntry() {\n const islands = await scanIslands(islandsDirPath);\n const entryPath = resolve(root, generatedEntry);\n const source = buildEntrySource(islands, entryPath, hydrateImport, routerImport, routerOptions);\n await mkdir(dirname(entryPath), { recursive: true });\n await writeFile(entryPath, source, \"utf8\");\n const entryMod = server.moduleGraph.getModuleById(entryPath);\n if (entryMod) server.moduleGraph.invalidateModule(entryMod);\n }\n\n server.watcher.on(\"change\", async (path) => {\n if (!isRelevant(path)) return;\n invalidate();\n const mod = server.moduleGraph.getModuleById(path);\n if (mod) server.moduleGraph.invalidateModule(mod);\n if (path.startsWith(islandsDirPath)) {\n await regenerateIslandEntry();\n console.log(\"[elur-kit] HMR reload islands after change:\", path);\n } else if (path.startsWith(contentDirPath) && path.endsWith(\".md\")) {\n console.log(\"[elur-kit] HMR content changed:\", path);\n } else if (path.includes(\".action.ts\") || path.includes(\".data.ts\") || path.includes(\"page.ts\") || path.includes(\"layout.ts\")) {\n console.log(\"[elur-kit] HMR reload routes/actions after change:\", path);\n }\n });\n\n server.watcher.on(\"add\", async (path) => {\n if (!isRelevant(path)) return;\n invalidate();\n if (path.startsWith(islandsDirPath)) {\n await regenerateIslandEntry();\n }\n console.log(\"[elur-kit] HMR new file detected:\", path);\n });\n\n server.watcher.on(\"unlink\", async (path) => {\n if (!isRelevant(path)) return;\n invalidate();\n const mod = server.moduleGraph.getModuleById(path);\n if (mod) server.moduleGraph.invalidateModule(mod);\n if (path.startsWith(islandsDirPath)) {\n await regenerateIslandEntry();\n }\n console.log(\"[elur-kit] HMR file removed:\", path);\n });\n}\n\nfunction createSsrLoader(server: ViteDevServer, root: string) {\n return (filePath: string) => {\n const rel = relative(root, filePath);\n const url = \"/\" + rel.split(\"\\\\\").join(\"/\");\n return server.ssrLoadModule(url);\n };\n}\n\nfunction createActionResolver(\n getActions: () => import(\"../action/scan.js\").ActionRegistry,\n getRoutes: () => Awaited<ReturnType<typeof scanRoutes>> | null,\n ssrLoad: (path: string) => Promise<unknown>,\n) {\n return async (name: string, page?: string) => {\n const actions = getActions();\n const routes = getRoutes();\n let pageKey: string | undefined;\n if (page && routes) {\n pageKey = routes.pages.some((route) => route.path === page)\n ? page\n : (matchRoute(page, routes.pages)?.route.path ?? page);\n }\n const pageActions = pageKey ? actions[pageKey] : Object.values(actions).find((p) => p[name]) ?? undefined;\n const actionPath = pageActions ? pageActions[name] : undefined;\n if (!actionPath) return undefined;\n const mod = (await ssrLoad(actionPath)) as Record<string, unknown>;\n const action = mod[name];\n if (typeof action === \"function\") {\n return action as (...args: unknown[]) => unknown;\n }\n return undefined;\n };\n}\n\nfunction readRequestBody(req: Connect.IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n let body = \"\";\n req.setEncoding(\"utf8\");\n req.on(\"data\", (chunk) => {\n body += chunk;\n });\n req.on(\"end\", () => resolve(body));\n req.on(\"error\", reject);\n });\n}\n\ninterface SsrHandlerOptions {\n routes: Awaited<ReturnType<typeof scanRoutes>> | null;\n actions: ActionRegistry;\n clientEntry: string;\n lang: string;\n ssrLoad: (path: string) => Promise<unknown>;\n middlewareHeaders?: Record<string, string>;\n}\n\nasync function handleSsrRequest(\n req: Connect.IncomingMessage,\n res: import(\"node:http\").ServerResponse,\n _next: Connect.NextFunction,\n options: SsrHandlerOptions,\n): Promise<boolean> {\n if (!options.routes) return false;\n const publicActions = actionNames(options.actions);\n\n let urlPath = req.url ?? \"/\";\n if (urlPath.includes(\"?\")) urlPath = urlPath.split(\"?\")[0];\n\n // Let Vite handle its own internals and assets.\n if (urlPath.startsWith(\"/@\") || urlPath.startsWith(\"/node_modules/\")) {\n return false;\n }\n\n // Skip explicit file requests.\n if (urlPath.includes(\".\")) return false;\n\n const config = { lang: options.lang, clientEntry: options.clientEntry };\n const match = matchRoute(urlPath, options.routes.pages);\n if (match) {\n try {\n const request = incomingMessageToRequest(req);\n if (options.middlewareHeaders) {\n for (const [name, value] of Object.entries(options.middlewareHeaders)) request.headers.set(name, value);\n }\n const { html, clearActionErrorCookie } = await renderPage({\n route: match.route,\n params: match.params,\n searchParams: new URLSearchParams(req.url?.split(\"?\")[1] ?? \"\"),\n config,\n importer: options.ssrLoad,\n actions: publicActions,\n request,\n });\n const responseHeaders: Record<string, string> = {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store, must-revalidate\",\n };\n if (clearActionErrorCookie) responseHeaders[\"Set-Cookie\"] = clearActionErrorCookie;\n res.writeHead(200, responseHeaders);\n res.end(html);\n return true;\n } catch (err) {\n console.error(\"[elur-kit] SSR render error:\", err);\n const errorResult = await renderErrorPage({\n routes: options.routes,\n status: 500,\n error: err,\n config,\n actions: publicActions,\n importer: options.ssrLoad,\n });\n if (errorResult) {\n res.writeHead(errorResult.status, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store, must-revalidate\",\n });\n res.end(errorResult.html);\n } else {\n res.writeHead(500, {\n \"Content-Type\": \"text/plain; charset=utf-8\",\n \"Cache-Control\": \"no-store, must-revalidate\",\n });\n res.end(String(err));\n }\n return true;\n }\n }\n\n const errorResult = await renderErrorPage({\n routes: options.routes,\n status: 404,\n config,\n actions: publicActions,\n importer: options.ssrLoad,\n });\n if (errorResult) {\n res.writeHead(errorResult.status, {\n \"Content-Type\": \"text/html; charset=utf-8\",\n \"Cache-Control\": \"no-store, must-revalidate\",\n });\n res.end(errorResult.html);\n return true;\n }\n\n return false;\n}\n"],"mappings":"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"}
@@ -18,6 +18,17 @@ export interface ElurJsKitViteOptions {
18
18
  hydrateImport?: string;
19
19
  /** Import specifier for startClientRouter in the generated entry. */
20
20
  routerImport?: string;
21
+ /**
22
+ * Client router flags baked into the generated dev entry. In dev the entry
23
+ * is never gated (HMR needs it on every page), but `enabled`/`prefetch`
24
+ * are honored so behavior matches production.
25
+ */
26
+ router?: {
27
+ enabled?: boolean;
28
+ prefetch?: boolean;
29
+ morph?: boolean;
30
+ loadingIndicator?: boolean;
31
+ };
21
32
  /** CSRF / origin policy applied to the server actions endpoint in dev. */
22
33
  actionSecurity?: ActionSecurityOptions;
23
34
  /**
@@ -18,6 +18,17 @@ export interface ElurJsKitViteOptions {
18
18
  hydrateImport?: string;
19
19
  /** Import specifier for startClientRouter in the generated entry. */
20
20
  routerImport?: string;
21
+ /**
22
+ * Client router flags baked into the generated dev entry. In dev the entry
23
+ * is never gated (HMR needs it on every page), but `enabled`/`prefetch`
24
+ * are honored so behavior matches production.
25
+ */
26
+ router?: {
27
+ enabled?: boolean;
28
+ prefetch?: boolean;
29
+ morph?: boolean;
30
+ loadingIndicator?: boolean;
31
+ };
21
32
  /** CSRF / origin policy applied to the server actions endpoint in dev. */
22
33
  actionSecurity?: ActionSecurityOptions;
23
34
  /**