@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,160 @@
1
+ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
+ import { mkdir as t, readFile as n, readdir as r, rename as i, rm as a, stat as o, writeFile as s } from "node:fs/promises";
3
+ import { dirname as c, join as l } from "node:path";
4
+ import { createHash as u, randomUUID as d } from "node:crypto";
5
+ //#region src/cache/adapter.ts
6
+ var f = /* @__PURE__ */ e({
7
+ cacheKey: () => p,
8
+ createFsCacheAdapter: () => m,
9
+ getWithSWR: () => h
10
+ });
11
+ function p(...e) {
12
+ return u("sha256").update(e.join("\n")).digest("hex");
13
+ }
14
+ function m(e) {
15
+ let { cacheDir: u } = e, f = e.maxEntries ?? 1e3, p = e.maxAgeMs ?? 864e5, m = /* @__PURE__ */ new Map(), h = l(u, "_tag-index.json");
16
+ async function g() {
17
+ try {
18
+ let e = await n(h, "utf8");
19
+ return JSON.parse(e);
20
+ } catch {
21
+ return {};
22
+ }
23
+ }
24
+ async function _(e) {
25
+ await t(c(h), { recursive: !0 });
26
+ let n = `${h}.${process.pid}.${d()}.tmp`;
27
+ try {
28
+ await s(n, JSON.stringify(e), "utf8"), await i(n, h);
29
+ } finally {
30
+ await a(n, { force: !0 });
31
+ }
32
+ }
33
+ function v(e) {
34
+ return l(u, `${e}.html.json`);
35
+ }
36
+ async function y(e) {
37
+ let t = m.get(e);
38
+ if (t) return t;
39
+ let r = (async () => {
40
+ try {
41
+ let t = await n(v(e), "utf8");
42
+ return JSON.parse(t);
43
+ } catch {
44
+ return null;
45
+ }
46
+ })();
47
+ m.set(e, r);
48
+ try {
49
+ return await r;
50
+ } finally {
51
+ m.delete(e);
52
+ }
53
+ }
54
+ async function b(e, n, r) {
55
+ let o = v(e);
56
+ await t(c(o), { recursive: !0 });
57
+ let l = {
58
+ html: n.html,
59
+ generatedAt: n.generatedAt ?? Date.now(),
60
+ revalidate: r.revalidate,
61
+ tags: r.tags,
62
+ version: r.version
63
+ }, u = `${o}.${process.pid}.${d()}.tmp`;
64
+ try {
65
+ await s(u, JSON.stringify(l), "utf8"), await i(u, o);
66
+ } finally {
67
+ await a(u, { force: !0 });
68
+ }
69
+ if (r.tags && r.tags.length > 0) {
70
+ let t = await g();
71
+ for (let n of r.tags) t[n] || (t[n] = []), t[n].includes(e) || t[n].push(e);
72
+ await _(t);
73
+ }
74
+ await w();
75
+ }
76
+ async function x(e) {
77
+ await a(v(e), { force: !0 });
78
+ }
79
+ async function S(e) {
80
+ if (e.length === 0) return;
81
+ let t = await g(), n = /* @__PURE__ */ new Set();
82
+ for (let r of e) {
83
+ let e = t[r];
84
+ if (e) {
85
+ for (let t of e) n.add(t);
86
+ delete t[r];
87
+ }
88
+ }
89
+ await Promise.all([...n].map((e) => x(e))), await _(t);
90
+ }
91
+ let C = 0;
92
+ async function w() {
93
+ let e = Date.now();
94
+ if (!(e - C < 6e4)) {
95
+ C = e;
96
+ try {
97
+ let t = await r(u), n = 0, i = [];
98
+ for (let r of t) {
99
+ if (!r.endsWith(".html.json")) continue;
100
+ n++;
101
+ let t = l(u, r);
102
+ try {
103
+ e - (await o(t)).mtimeMs > p && i.push(t);
104
+ } catch {}
105
+ }
106
+ if (n - i.length > f) {
107
+ let e = [];
108
+ for (let n of t) {
109
+ if (!n.endsWith(".html.json")) continue;
110
+ let t = l(u, n);
111
+ if (!i.includes(t)) try {
112
+ let n = await o(t);
113
+ e.push({
114
+ path: t,
115
+ mtime: n.mtimeMs
116
+ });
117
+ } catch {}
118
+ }
119
+ e.sort((e, t) => e.mtime - t.mtime);
120
+ let r = n - i.length - f;
121
+ for (let t = 0; t < r && t < e.length; t++) i.push(e[t].path);
122
+ }
123
+ await Promise.all(i.map((e) => a(e, { force: !0 })));
124
+ } catch {}
125
+ }
126
+ }
127
+ return {
128
+ get: y,
129
+ set: b,
130
+ delete: x,
131
+ invalidateTags: S
132
+ };
133
+ }
134
+ async function h(e, t, n) {
135
+ let r = await e.get(t);
136
+ return r ? Date.now() - r.generatedAt >= r.revalidate * 1e3 ? (n().then((n) => {
137
+ n && e.set(t, n, {
138
+ revalidate: r.revalidate,
139
+ tags: r.tags,
140
+ version: r.version
141
+ }).catch((e) => {
142
+ console.error("[elur-kit] background cache write failed:", e);
143
+ });
144
+ }, (e) => {
145
+ console.error("[elur-kit] background revalidation failed:", e);
146
+ }), {
147
+ entry: r,
148
+ stale: !0
149
+ }) : {
150
+ entry: r,
151
+ stale: !1
152
+ } : {
153
+ entry: await n(),
154
+ stale: !1
155
+ };
156
+ }
157
+ //#endregion
158
+ export { h as i, p as n, m as r, f as t };
159
+
160
+ //# sourceMappingURL=adapter-DNsjXvq5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-DNsjXvq5.js","names":[],"sources":["../../src/cache/adapter.ts"],"sourcesContent":["// --- CacheAdapter: pluggable cache with single-flight, SWR, tags (§9.2) ---\n//\n// Implements the CacheAdapter interface from the runtime-security design:\n// - SHA-256 keys for normalized identity\n// - temp + atomic rename writes\n// - single-flight per process (deduplicates concurrent gets for same key)\n// - stale-while-revalidate (serves stale, refreshes in background)\n// - tag-based invalidation\n// - size limits and periodic cleanup\n//\n// The filesystem adapter is the default. External adapters (Redis, KV, etc.)\n// can implement the same interface and be plugged in via config.\n\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, writeFile, readdir, stat } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\n// Types\n\nexport interface CacheEntry {\n html: string;\n generatedAt: number;\n revalidate: number;\n tags?: string[];\n version?: string;\n}\n\nexport interface CacheWriteOptions {\n revalidate: number;\n tags?: string[];\n version?: string;\n}\n\nexport interface CacheAdapter {\n get(key: string): Promise<CacheEntry | null>;\n set(key: string, value: CacheEntry, options: CacheWriteOptions): Promise<void>;\n delete(key: string): Promise<void>;\n invalidateTags(tags: readonly string[]): Promise<void>;\n}\n\n// Helpers\n\n/** Computes a SHA-256 key from a normalized identity string. */\nexport function cacheKey(...parts: string[]): string {\n return createHash(\"sha256\").update(parts.join(\"\\n\")).digest(\"hex\");\n}\n\n// Filesystem CacheAdapter\n\nexport interface FsCacheAdapterOptions {\n cacheDir: string;\n /** Max entries before cleanup runs. Default: 1000. */\n maxEntries?: number;\n /** Max age in ms for entries. Default: 24h. */\n maxAgeMs?: number;\n}\n\nexport function createFsCacheAdapter(options: FsCacheAdapterOptions): CacheAdapter {\n const { cacheDir } = options;\n const maxEntries = options.maxEntries ?? 1000;\n const maxAgeMs = options.maxAgeMs ?? 24 * 60 * 60 * 1000;\n\n // Single-flight: deduplicates concurrent gets for the same key.\n const inFlight = new Map<string, Promise<CacheEntry | null>>();\n\n // Tag index: maps tag -> set of cache keys.\n // Persisted to a JSON file for cross-process visibility.\n const tagIndexPath = join(cacheDir, \"_tag-index.json\");\n\n async function loadTagIndex(): Promise<Record<string, string[]>> {\n try {\n const raw = await readFile(tagIndexPath, \"utf8\");\n return JSON.parse(raw) as Record<string, string[]>;\n } catch {\n return {};\n }\n }\n\n async function saveTagIndex(index: Record<string, string[]>): Promise<void> {\n await mkdir(dirname(tagIndexPath), { recursive: true });\n const tmp = `${tagIndexPath}.${process.pid}.${randomUUID()}.tmp`;\n try {\n await writeFile(tmp, JSON.stringify(index), \"utf8\");\n await rename(tmp, tagIndexPath);\n } finally {\n await rm(tmp, { force: true });\n }\n }\n\n function entryPath(key: string): string {\n return join(cacheDir, `${key}.html.json`);\n }\n\n async function get(key: string): Promise<CacheEntry | null> {\n // Single-flight: if a get is already in progress for this key, wait for it.\n const existing = inFlight.get(key);\n if (existing) return existing;\n\n const promise = (async () => {\n try {\n const raw = await readFile(entryPath(key), \"utf8\");\n const entry = JSON.parse(raw) as CacheEntry;\n return entry;\n } catch {\n return null;\n }\n })();\n\n inFlight.set(key, promise);\n try {\n return await promise;\n } finally {\n inFlight.delete(key);\n }\n }\n\n async function set(key: string, value: CacheEntry, opts: CacheWriteOptions): Promise<void> {\n const path = entryPath(key);\n await mkdir(dirname(path), { recursive: true });\n\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\n // Atomic write: temp + rename.\n const tmp = `${path}.${process.pid}.${randomUUID()}.tmp`;\n try {\n await writeFile(tmp, JSON.stringify(entry), \"utf8\");\n await rename(tmp, path);\n } finally {\n await rm(tmp, { force: true });\n }\n\n // Update tag index.\n if (opts.tags && opts.tags.length > 0) {\n const index = await loadTagIndex();\n for (const tag of opts.tags) {\n if (!index[tag]) index[tag] = [];\n if (!index[tag].includes(key)) index[tag].push(key);\n }\n await saveTagIndex(index);\n }\n\n // Periodic cleanup.\n await maybeCleanup();\n }\n\n async function del(key: string): Promise<void> {\n await rm(entryPath(key), { force: true });\n }\n\n async function invalidateTags(tags: readonly string[]): Promise<void> {\n if (tags.length === 0) return;\n const index = await loadTagIndex();\n const keysToDelete = new Set<string>();\n for (const tag of tags) {\n const keys = index[tag];\n if (keys) {\n for (const key of keys) keysToDelete.add(key);\n delete index[tag];\n }\n }\n await Promise.all([...keysToDelete].map((key) => del(key)));\n await saveTagIndex(index);\n }\n\n let lastCleanup = 0;\n async function maybeCleanup(): Promise<void> {\n const now = Date.now();\n if (now - lastCleanup < 60_000) return; // at most once per minute\n lastCleanup = now;\n try {\n const files = await readdir(cacheDir);\n let entryCount = 0;\n const toDelete: string[] = [];\n for (const file of files) {\n if (!file.endsWith(\".html.json\")) continue;\n entryCount++;\n const filePath = join(cacheDir, file);\n try {\n const stats = await stat(filePath);\n if (now - stats.mtimeMs > maxAgeMs) {\n toDelete.push(filePath);\n }\n } catch {\n // stat failed, skip\n }\n }\n // If over limit, delete oldest (by mtime).\n if (entryCount - toDelete.length > maxEntries) {\n const candidates: Array<{ path: string; mtime: number }> = [];\n for (const file of files) {\n if (!file.endsWith(\".html.json\")) continue;\n const filePath = join(cacheDir, file);\n if (toDelete.includes(filePath)) continue;\n try {\n const stats = await stat(filePath);\n candidates.push({ path: filePath, mtime: stats.mtimeMs });\n } catch {\n // skip\n }\n }\n candidates.sort((a, b) => a.mtime - b.mtime);\n const excess = entryCount - toDelete.length - maxEntries;\n for (let i = 0; i < excess && i < candidates.length; i++) {\n toDelete.push(candidates[i].path);\n }\n }\n await Promise.all(toDelete.map((p) => rm(p, { force: true })));\n } catch {\n // cleanup is best-effort\n }\n }\n\n return { get, set, delete: del, invalidateTags };\n}\n\n// Stale-while-revalidate wrapper\n\n/**\n * Gets a cached entry. If the entry is stale (past revalidate), serves it\n * immediately and triggers a background revalidation.\n *\n * @param adapter The cache adapter.\n * @param key The cache key.\n * @param revalidate The revalidation function (called if stale or missing).\n * @returns The cache entry (fresh or stale), or null if missing.\n */\nexport async function getWithSWR(\n adapter: CacheAdapter,\n key: string,\n revalidate: () => Promise<CacheEntry | null>,\n): Promise<{ entry: CacheEntry | null; stale: boolean }> {\n const entry = await adapter.get(key);\n if (!entry) {\n // Cache miss: revalidate synchronously.\n const fresh = await revalidate();\n return { entry: fresh, stale: false };\n }\n\n const ageMs = Date.now() - entry.generatedAt;\n const isStale = ageMs >= entry.revalidate * 1000;\n\n if (isStale) {\n // Serve stale, revalidate in background (fire-and-forget).\n revalidate().then(\n (fresh) => {\n if (fresh) {\n adapter.set(key, fresh, {\n revalidate: entry.revalidate,\n tags: entry.tags,\n version: entry.version,\n }).catch((err) => {\n console.error(\"[elur-kit] background cache write failed:\", err);\n });\n }\n },\n (err) => {\n console.error(\"[elur-kit] background revalidation failed:\", err);\n },\n );\n return { entry, stale: true };\n }\n\n return { entry, stale: false };\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ const e=require("./rolldown-runtime-BIInC43l.cjs");let t=require("node:fs/promises"),n=require("node:path"),r=require("node:crypto");var i=e.t({cacheKey:()=>a,createFsCacheAdapter:()=>o,getWithSWR:()=>s});function a(...e){return(0,r.createHash)(`sha256`).update(e.join(`
2
+ `)).digest(`hex`)}function o(e){let{cacheDir:i}=e,a=e.maxEntries??1e3,o=e.maxAgeMs??864e5,s=new Map,c=(0,n.join)(i,`_tag-index.json`);async function l(){try{let e=await(0,t.readFile)(c,`utf8`);return JSON.parse(e)}catch{return{}}}async function u(e){await(0,t.mkdir)((0,n.dirname)(c),{recursive:!0});let i=`${c}.${process.pid}.${(0,r.randomUUID)()}.tmp`;try{await(0,t.writeFile)(i,JSON.stringify(e),`utf8`),await(0,t.rename)(i,c)}finally{await(0,t.rm)(i,{force:!0})}}function d(e){return(0,n.join)(i,`${e}.html.json`)}async function f(e){let n=s.get(e);if(n)return n;let r=(async()=>{try{let n=await(0,t.readFile)(d(e),`utf8`);return JSON.parse(n)}catch{return null}})();s.set(e,r);try{return await r}finally{s.delete(e)}}async function p(e,i,a){let o=d(e);await(0,t.mkdir)((0,n.dirname)(o),{recursive:!0});let s={html:i.html,generatedAt:i.generatedAt??Date.now(),revalidate:a.revalidate,tags:a.tags,version:a.version},c=`${o}.${process.pid}.${(0,r.randomUUID)()}.tmp`;try{await(0,t.writeFile)(c,JSON.stringify(s),`utf8`),await(0,t.rename)(c,o)}finally{await(0,t.rm)(c,{force:!0})}if(a.tags&&a.tags.length>0){let t=await l();for(let n of a.tags)t[n]||(t[n]=[]),t[n].includes(e)||t[n].push(e);await u(t)}await _()}async function m(e){await(0,t.rm)(d(e),{force:!0})}async function h(e){if(e.length===0)return;let t=await l(),n=new Set;for(let r of e){let e=t[r];if(e){for(let t of e)n.add(t);delete t[r]}}await Promise.all([...n].map(e=>m(e))),await u(t)}let g=0;async function _(){let e=Date.now();if(!(e-g<6e4)){g=e;try{let r=await(0,t.readdir)(i),s=0,c=[];for(let a of r){if(!a.endsWith(`.html.json`))continue;s++;let r=(0,n.join)(i,a);try{e-(await(0,t.stat)(r)).mtimeMs>o&&c.push(r)}catch{}}if(s-c.length>a){let e=[];for(let a of r){if(!a.endsWith(`.html.json`))continue;let r=(0,n.join)(i,a);if(!c.includes(r))try{let n=await(0,t.stat)(r);e.push({path:r,mtime:n.mtimeMs})}catch{}}e.sort((e,t)=>e.mtime-t.mtime);let o=s-c.length-a;for(let t=0;t<o&&t<e.length;t++)c.push(e[t].path)}await Promise.all(c.map(e=>(0,t.rm)(e,{force:!0})))}catch{}}}return{get:f,set:p,delete:m,invalidateTags:h}}async function s(e,t,n){let r=await e.get(t);return r?Date.now()-r.generatedAt>=r.revalidate*1e3?(n().then(n=>{n&&e.set(t,n,{revalidate:r.revalidate,tags:r.tags,version:r.version}).catch(e=>{console.error(`[elur-kit] background cache write failed:`,e)})},e=>{console.error(`[elur-kit] background revalidation failed:`,e)}),{entry:r,stale:!0}):{entry:r,stale:!1}:{entry:await n(),stale:!1}}Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return i}});
3
+ //# sourceMappingURL=adapter-Dz2hzR36.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-Dz2hzR36.cjs","names":[],"sources":["../../src/cache/adapter.ts"],"sourcesContent":["// --- CacheAdapter: pluggable cache with single-flight, SWR, tags (§9.2) ---\n//\n// Implements the CacheAdapter interface from the runtime-security design:\n// - SHA-256 keys for normalized identity\n// - temp + atomic rename writes\n// - single-flight per process (deduplicates concurrent gets for same key)\n// - stale-while-revalidate (serves stale, refreshes in background)\n// - tag-based invalidation\n// - size limits and periodic cleanup\n//\n// The filesystem adapter is the default. External adapters (Redis, KV, etc.)\n// can implement the same interface and be plugged in via config.\n\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, writeFile, readdir, stat } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\n// Types\n\nexport interface CacheEntry {\n html: string;\n generatedAt: number;\n revalidate: number;\n tags?: string[];\n version?: string;\n}\n\nexport interface CacheWriteOptions {\n revalidate: number;\n tags?: string[];\n version?: string;\n}\n\nexport interface CacheAdapter {\n get(key: string): Promise<CacheEntry | null>;\n set(key: string, value: CacheEntry, options: CacheWriteOptions): Promise<void>;\n delete(key: string): Promise<void>;\n invalidateTags(tags: readonly string[]): Promise<void>;\n}\n\n// Helpers\n\n/** Computes a SHA-256 key from a normalized identity string. */\nexport function cacheKey(...parts: string[]): string {\n return createHash(\"sha256\").update(parts.join(\"\\n\")).digest(\"hex\");\n}\n\n// Filesystem CacheAdapter\n\nexport interface FsCacheAdapterOptions {\n cacheDir: string;\n /** Max entries before cleanup runs. Default: 1000. */\n maxEntries?: number;\n /** Max age in ms for entries. Default: 24h. */\n maxAgeMs?: number;\n}\n\nexport function createFsCacheAdapter(options: FsCacheAdapterOptions): CacheAdapter {\n const { cacheDir } = options;\n const maxEntries = options.maxEntries ?? 1000;\n const maxAgeMs = options.maxAgeMs ?? 24 * 60 * 60 * 1000;\n\n // Single-flight: deduplicates concurrent gets for the same key.\n const inFlight = new Map<string, Promise<CacheEntry | null>>();\n\n // Tag index: maps tag -> set of cache keys.\n // Persisted to a JSON file for cross-process visibility.\n const tagIndexPath = join(cacheDir, \"_tag-index.json\");\n\n async function loadTagIndex(): Promise<Record<string, string[]>> {\n try {\n const raw = await readFile(tagIndexPath, \"utf8\");\n return JSON.parse(raw) as Record<string, string[]>;\n } catch {\n return {};\n }\n }\n\n async function saveTagIndex(index: Record<string, string[]>): Promise<void> {\n await mkdir(dirname(tagIndexPath), { recursive: true });\n const tmp = `${tagIndexPath}.${process.pid}.${randomUUID()}.tmp`;\n try {\n await writeFile(tmp, JSON.stringify(index), \"utf8\");\n await rename(tmp, tagIndexPath);\n } finally {\n await rm(tmp, { force: true });\n }\n }\n\n function entryPath(key: string): string {\n return join(cacheDir, `${key}.html.json`);\n }\n\n async function get(key: string): Promise<CacheEntry | null> {\n // Single-flight: if a get is already in progress for this key, wait for it.\n const existing = inFlight.get(key);\n if (existing) return existing;\n\n const promise = (async () => {\n try {\n const raw = await readFile(entryPath(key), \"utf8\");\n const entry = JSON.parse(raw) as CacheEntry;\n return entry;\n } catch {\n return null;\n }\n })();\n\n inFlight.set(key, promise);\n try {\n return await promise;\n } finally {\n inFlight.delete(key);\n }\n }\n\n async function set(key: string, value: CacheEntry, opts: CacheWriteOptions): Promise<void> {\n const path = entryPath(key);\n await mkdir(dirname(path), { recursive: true });\n\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\n // Atomic write: temp + rename.\n const tmp = `${path}.${process.pid}.${randomUUID()}.tmp`;\n try {\n await writeFile(tmp, JSON.stringify(entry), \"utf8\");\n await rename(tmp, path);\n } finally {\n await rm(tmp, { force: true });\n }\n\n // Update tag index.\n if (opts.tags && opts.tags.length > 0) {\n const index = await loadTagIndex();\n for (const tag of opts.tags) {\n if (!index[tag]) index[tag] = [];\n if (!index[tag].includes(key)) index[tag].push(key);\n }\n await saveTagIndex(index);\n }\n\n // Periodic cleanup.\n await maybeCleanup();\n }\n\n async function del(key: string): Promise<void> {\n await rm(entryPath(key), { force: true });\n }\n\n async function invalidateTags(tags: readonly string[]): Promise<void> {\n if (tags.length === 0) return;\n const index = await loadTagIndex();\n const keysToDelete = new Set<string>();\n for (const tag of tags) {\n const keys = index[tag];\n if (keys) {\n for (const key of keys) keysToDelete.add(key);\n delete index[tag];\n }\n }\n await Promise.all([...keysToDelete].map((key) => del(key)));\n await saveTagIndex(index);\n }\n\n let lastCleanup = 0;\n async function maybeCleanup(): Promise<void> {\n const now = Date.now();\n if (now - lastCleanup < 60_000) return; // at most once per minute\n lastCleanup = now;\n try {\n const files = await readdir(cacheDir);\n let entryCount = 0;\n const toDelete: string[] = [];\n for (const file of files) {\n if (!file.endsWith(\".html.json\")) continue;\n entryCount++;\n const filePath = join(cacheDir, file);\n try {\n const stats = await stat(filePath);\n if (now - stats.mtimeMs > maxAgeMs) {\n toDelete.push(filePath);\n }\n } catch {\n // stat failed, skip\n }\n }\n // If over limit, delete oldest (by mtime).\n if (entryCount - toDelete.length > maxEntries) {\n const candidates: Array<{ path: string; mtime: number }> = [];\n for (const file of files) {\n if (!file.endsWith(\".html.json\")) continue;\n const filePath = join(cacheDir, file);\n if (toDelete.includes(filePath)) continue;\n try {\n const stats = await stat(filePath);\n candidates.push({ path: filePath, mtime: stats.mtimeMs });\n } catch {\n // skip\n }\n }\n candidates.sort((a, b) => a.mtime - b.mtime);\n const excess = entryCount - toDelete.length - maxEntries;\n for (let i = 0; i < excess && i < candidates.length; i++) {\n toDelete.push(candidates[i].path);\n }\n }\n await Promise.all(toDelete.map((p) => rm(p, { force: true })));\n } catch {\n // cleanup is best-effort\n }\n }\n\n return { get, set, delete: del, invalidateTags };\n}\n\n// Stale-while-revalidate wrapper\n\n/**\n * Gets a cached entry. If the entry is stale (past revalidate), serves it\n * immediately and triggers a background revalidation.\n *\n * @param adapter The cache adapter.\n * @param key The cache key.\n * @param revalidate The revalidation function (called if stale or missing).\n * @returns The cache entry (fresh or stale), or null if missing.\n */\nexport async function getWithSWR(\n adapter: CacheAdapter,\n key: string,\n revalidate: () => Promise<CacheEntry | null>,\n): Promise<{ entry: CacheEntry | null; stale: boolean }> {\n const entry = await adapter.get(key);\n if (!entry) {\n // Cache miss: revalidate synchronously.\n const fresh = await revalidate();\n return { entry: fresh, stale: false };\n }\n\n const ageMs = Date.now() - entry.generatedAt;\n const isStale = ageMs >= entry.revalidate * 1000;\n\n if (isStale) {\n // Serve stale, revalidate in background (fire-and-forget).\n revalidate().then(\n (fresh) => {\n if (fresh) {\n adapter.set(key, fresh, {\n revalidate: entry.revalidate,\n tags: entry.tags,\n version: entry.version,\n }).catch((err) => {\n console.error(\"[elur-kit] background cache write failed:\", err);\n });\n }\n },\n (err) => {\n console.error(\"[elur-kit] background revalidation failed:\", err);\n },\n );\n return { entry, stale: true };\n }\n\n return { entry, stale: false };\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
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");var a={name:`bun`,capabilities:n.t,async build(n){let a=(0,i.resolve)(n.root),c=(0,i.resolve)(a,n.outDir),l=(0,i.resolve)(a,`.elur`);try{await(0,r.stat)(c)}catch{throw Error(`Output directory not found: ${c}. Run "elur-kit build" first.`)}await(0,r.rm)(l,{recursive:!0,force:!0}),await(0,r.mkdir)(l,{recursive:!0});let u=(0,i.resolve)(a,n.appDir),d=await e.t(u),f=(0,i.resolve)(l,`bun-index.ts`);await t.n(f,d,n);let p=(0,i.resolve)(l,`bun-server.ts`);await(0,r.writeFile)(p,o(s(l,c),n),`utf8`)}};function o(e,t){return`// AUTO-GENERATED by @elurjs/kit. Do not edit.
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");var a={name:`bun`,capabilities:t.t,async build(t){let a=(0,i.resolve)(t.root),c=(0,i.resolve)(a,t.outDir),l=(0,i.resolve)(a,`.elur`);try{await(0,r.stat)(c)}catch{throw Error(`Output directory not found: ${c}. Run "elur-kit build" first.`)}await(0,r.rm)(l,{recursive:!0,force:!0}),await(0,r.mkdir)(l,{recursive:!0});let u=(0,i.resolve)(a,t.appDir),d=await e.t(u),f=(0,i.resolve)(l,`bun-index.ts`);await n.n(f,d,t);let p=(0,i.resolve)(l,`bun-server.ts`);await(0,r.writeFile)(p,o(s(l,c),t),`utf8`)}};function o(e,t){let n=t.logLevel?`, logLevel: ${JSON.stringify(t.logLevel)}`:``,r=[`redirects`,`rewrites`,`routeHeaders`].map(e=>{let n=t[e];return n&&n.length>0?`, ${e}: ${JSON.stringify(n)}`:``}).join(``);return`// AUTO-GENERATED by @elurjs/kit. Do not edit.
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { createWebHandler } from "@elurjs/kit/runtime";
4
4
  import handler from "./bun-index.ts";
@@ -9,7 +9,7 @@ const port = Number(process.env.PORT) || ${t.port??3e3};
9
9
  const webHandler = createWebHandler(
10
10
  { pages: [], api: [], error404: undefined, error500: undefined },
11
11
  {},
12
- { staticRoot: outDir, lang: ${JSON.stringify(t.lang)}, clientEntry: ${JSON.stringify(t.clientEntry)} },
12
+ { staticRoot: outDir, lang: ${JSON.stringify(t.lang)}, clientEntry: ${JSON.stringify(t.clientEntry)}${n}${r} },
13
13
  );
14
14
 
15
15
  Bun.serve({
@@ -1 +1 @@
1
- {"version":3,"file":"bun.cjs","names":[],"sources":["../../../src/adapters/bun.ts"],"sourcesContent":["import { mkdir, rm, stat, writeFile } from \"node:fs/promises\";\nimport { relative, resolve } from \"node:path\";\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 * Bun adapter for elur-kit.\n *\n * Produces a self-contained Bun server entry at `.elur/bun-server.ts`.\n * Run it with:\n *\n * bun run .elur/bun-server.ts\n *\n * The server serves static files from `dist/` and renders pages on demand for\n * unmatched routes.\n */\nexport const bunAdapter: Adapter = {\n name: \"bun\",\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 // Verify the production build exists.\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 // Clean previous adapter output.\n await rm(generatedDir, { recursive: true, force: true });\n await mkdir(generatedDir, { recursive: true });\n\n // Scan routes and generate a self-contained SSR handler entry.\n const appDir = resolve(root, options.appDir);\n const routes = await scanRoutes(appDir);\n\n const entryPath = resolve(generatedDir, \"bun-index.ts\");\n await writeSsrEntry(entryPath, routes, options);\n\n // Write the Bun server entry.\n const serverPath = resolve(generatedDir, \"bun-server.ts\");\n await writeFile(\n serverPath,\n buildBunServerSource(relativeToUrlPath(generatedDir, outDir), options),\n \"utf8\",\n );\n },\n};\n\nfunction buildBunServerSource(\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 { fileURLToPath } from \"node:url\";\nimport { createWebHandler } from \"@elurjs/kit/runtime\";\nimport handler from \"./bun-index.ts\";\n\nconst outDir = fileURLToPath(new URL(${JSON.stringify(outDirUrl)}, import.meta.url));\nconst port = Number(process.env.PORT) || ${options.port ?? 3000};\n\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\nBun.serve({\n port,\n async fetch(request) {\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 return response;\n },\n});\n\nconsole.log(\\`Bun server running at http://localhost:\\${port}\\`);\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":"2PAkBA,IAAa,EAAsB,CACjC,KAAM,MACN,aAAc,EAAA,EAEd,MAAM,MAAM,EAAS,CACnB,IAAM,GAAA,EAAO,EAAA,QAAA,CAAQ,EAAQ,IAAI,EAC3B,GAAA,EAAS,EAAA,QAAA,CAAQ,EAAM,EAAQ,MAAM,EACrC,GAAA,EAAe,EAAA,QAAA,CAAQ,EAAM,OAAO,EAG1C,GAAI,CACF,MAAA,EAAM,EAAA,KAAA,CAAK,CAAM,CACnB,MAAQ,CACN,MAAU,MACR,+BAA+B,EAAO,8BACxC,CACF,CAGA,MAAA,EAAM,EAAA,GAAA,CAAG,EAAc,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EACvD,MAAA,EAAM,EAAA,MAAA,CAAM,EAAc,CAAE,UAAW,EAAK,CAAC,EAG7C,IAAM,GAAA,EAAS,EAAA,QAAA,CAAQ,EAAM,EAAQ,MAAM,EACrC,EAAS,MAAM,EAAA,EAAW,CAAM,EAEhC,GAAA,EAAY,EAAA,QAAA,CAAQ,EAAc,cAAc,EACtD,MAAM,EAAA,EAAc,EAAW,EAAQ,CAAO,EAG9C,IAAM,GAAA,EAAa,EAAA,QAAA,CAAQ,EAAc,eAAe,EACxD,MAAA,EAAM,EAAA,UAAA,CACJ,EACA,EAAqB,EAAkB,EAAc,CAAM,EAAG,CAAO,EACrE,MACF,CACF,CACF,EAEA,SAAS,EACP,EACA,EAKQ,CACR,MAAO;;;;;uCAK8B,KAAK,UAAU,CAAS,EAAE;2CACtB,EAAQ,MAAQ,IAAK;;;;;gCAKhC,KAAK,UAAU,EAAQ,IAAI,EAAE,iBAAiB,KAAK,UAAU,EAAQ,WAAW,EAAE;;;;;;;;;;;;;;;;;CAkBlH,CAEA,SAAS,EAAkB,EAAc,EAAoB,CAC3D,IAAM,GAAA,EAAO,EAAA,SAAA,CAAS,EAAM,CAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,GAAG,EACpD,MAAO,GAAG,EAAK,WAAW,GAAG,EAAI,EAAO,KAAK,IAAO,EACtD"}
1
+ {"version":3,"file":"bun.cjs","names":[],"sources":["../../../src/adapters/bun.ts"],"sourcesContent":["import { mkdir, rm, stat, writeFile } from \"node:fs/promises\";\nimport { relative, resolve } from \"node:path\";\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 * Bun adapter for elur-kit.\n *\n * Produces a self-contained Bun server entry at `.elur/bun-server.ts`.\n * Run it with:\n *\n * bun run .elur/bun-server.ts\n *\n * The server serves static files from `dist/` and renders pages on demand for\n * unmatched routes.\n */\nexport const bunAdapter: Adapter = {\n name: \"bun\",\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 // Verify the production build exists.\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 // Clean previous adapter output.\n await rm(generatedDir, { recursive: true, force: true });\n await mkdir(generatedDir, { recursive: true });\n\n // Scan routes and generate a self-contained SSR handler entry.\n const appDir = resolve(root, options.appDir);\n const routes = await scanRoutes(appDir);\n\n const entryPath = resolve(generatedDir, \"bun-index.ts\");\n await writeSsrEntry(entryPath, routes, options);\n\n // Write the Bun server entry.\n const serverPath = resolve(generatedDir, \"bun-server.ts\");\n await writeFile(\n serverPath,\n buildBunServerSource(relativeToUrlPath(generatedDir, outDir), options),\n \"utf8\",\n );\n },\n};\n\nfunction buildBunServerSource(\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 { fileURLToPath } from \"node:url\";\nimport { createWebHandler } from \"@elurjs/kit/runtime\";\nimport handler from \"./bun-index.ts\";\n\nconst outDir = fileURLToPath(new URL(${JSON.stringify(outDirUrl)}, import.meta.url));\nconst port = Number(process.env.PORT) || ${options.port ?? 3000};\n\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\nBun.serve({\n port,\n async fetch(request) {\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 return response;\n },\n});\n\nconsole.log(\\`Bun server running at http://localhost:\\${port}\\`);\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":"2PAkBA,IAAa,EAAsB,CACjC,KAAM,MACN,aAAc,EAAA,EAEd,MAAM,MAAM,EAAS,CACnB,IAAM,GAAA,EAAO,EAAA,QAAA,CAAQ,EAAQ,IAAI,EAC3B,GAAA,EAAS,EAAA,QAAA,CAAQ,EAAM,EAAQ,MAAM,EACrC,GAAA,EAAe,EAAA,QAAA,CAAQ,EAAM,OAAO,EAG1C,GAAI,CACF,MAAA,EAAM,EAAA,KAAA,CAAK,CAAM,CACnB,MAAQ,CACN,MAAU,MACR,+BAA+B,EAAO,8BACxC,CACF,CAGA,MAAA,EAAM,EAAA,GAAA,CAAG,EAAc,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EACvD,MAAA,EAAM,EAAA,MAAA,CAAM,EAAc,CAAE,UAAW,EAAK,CAAC,EAG7C,IAAM,GAAA,EAAS,EAAA,QAAA,CAAQ,EAAM,EAAQ,MAAM,EACrC,EAAS,MAAM,EAAA,EAAW,CAAM,EAEhC,GAAA,EAAY,EAAA,QAAA,CAAQ,EAAc,cAAc,EACtD,MAAM,EAAA,EAAc,EAAW,EAAQ,CAAO,EAG9C,IAAM,GAAA,EAAa,EAAA,QAAA,CAAQ,EAAc,eAAe,EACxD,MAAA,EAAM,EAAA,UAAA,CACJ,EACA,EAAqB,EAAkB,EAAc,CAAM,EAAG,CAAO,EACrE,MACF,CACF,CACF,EAEA,SAAS,EACP,EACA,EASQ,CACR,IAAM,EAAiB,EAAQ,SAAW,eAAe,KAAK,UAAU,EAAQ,QAAQ,IAAM,GAExF,EAAkB,CAAC,YAAa,WAAY,cAAc,CAAC,CAC9D,IAAK,GAAQ,CACZ,IAAM,EAAQ,EAAQ,GACtB,OAAO,GAAS,EAAM,OAAS,EAAI,KAAK,EAAI,IAAI,KAAK,UAAU,CAAK,IAAM,EAC5E,CAAC,CAAC,CACD,KAAK,EAAE,EACV,MAAO;;;;;uCAK8B,KAAK,UAAU,CAAS,EAAE;2CACtB,EAAQ,MAAQ,IAAK;;;;;gCAKhC,KAAK,UAAU,EAAQ,IAAI,EAAE,iBAAiB,KAAK,UAAU,EAAQ,WAAW,IAAI,IAAiB,EAAe;;;;;;;;;;;;;;;;;CAkBpJ,CAEA,SAAS,EAAkB,EAAc,EAAoB,CAC3D,IAAM,GAAA,EAAO,EAAA,SAAA,CAAS,EAAM,CAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,GAAG,EACpD,MAAO,GAAG,EAAK,WAAW,GAAG,EAAI,EAAO,KAAK,IAAO,EACtD"}
@@ -1,14 +1,14 @@
1
1
  import { t as e } from "../route-scanner-XcLId7lK.js";
2
- import { n as t } from "../shared-DU3iQgr7.js";
3
- import { t as n } from "../capabilities-C7txofmY.js";
2
+ import { t } from "../capabilities-C7txofmY.js";
3
+ import { n } from "../shared-D8w-neq2.js";
4
4
  import { mkdir as r, rm as i, stat as a, writeFile as o } from "node:fs/promises";
5
5
  import { relative as s, resolve as c } from "node:path";
6
6
  //#region src/adapters/bun.ts
7
7
  var l = {
8
8
  name: "bun",
9
- capabilities: n,
10
- async build(n) {
11
- let s = c(n.root), l = c(s, n.outDir), f = c(s, ".elur");
9
+ capabilities: t,
10
+ async build(t) {
11
+ let s = c(t.root), l = c(s, t.outDir), f = c(s, ".elur");
12
12
  try {
13
13
  await a(l);
14
14
  } catch {
@@ -18,13 +18,21 @@ var l = {
18
18
  recursive: !0,
19
19
  force: !0
20
20
  }), await r(f, { recursive: !0 });
21
- let p = c(s, n.appDir), m = await e(p), h = c(f, "bun-index.ts");
22
- await t(h, m, n);
21
+ let p = c(s, t.appDir), m = await e(p), h = c(f, "bun-index.ts");
22
+ await n(h, m, t);
23
23
  let g = c(f, "bun-server.ts");
24
- await o(g, u(d(f, l), n), "utf8");
24
+ await o(g, u(d(f, l), t), "utf8");
25
25
  }
26
26
  };
27
27
  function u(e, t) {
28
+ let n = t.logLevel ? `, logLevel: ${JSON.stringify(t.logLevel)}` : "", r = [
29
+ "redirects",
30
+ "rewrites",
31
+ "routeHeaders"
32
+ ].map((e) => {
33
+ let n = t[e];
34
+ return n && n.length > 0 ? `, ${e}: ${JSON.stringify(n)}` : "";
35
+ }).join("");
28
36
  return `// AUTO-GENERATED by @elurjs/kit. Do not edit.
29
37
  import { fileURLToPath } from "node:url";
30
38
  import { createWebHandler } from "@elurjs/kit/runtime";
@@ -36,7 +44,7 @@ const port = Number(process.env.PORT) || ${t.port ?? 3e3};
36
44
  const webHandler = createWebHandler(
37
45
  { pages: [], api: [], error404: undefined, error500: undefined },
38
46
  {},
39
- { staticRoot: outDir, lang: ${JSON.stringify(t.lang)}, clientEntry: ${JSON.stringify(t.clientEntry)} },
47
+ { staticRoot: outDir, lang: ${JSON.stringify(t.lang)}, clientEntry: ${JSON.stringify(t.clientEntry)}${n}${r} },
40
48
  );
41
49
 
42
50
  Bun.serve({
@@ -1 +1 @@
1
- {"version":3,"file":"bun.js","names":[],"sources":["../../../src/adapters/bun.ts"],"sourcesContent":["import { mkdir, rm, stat, writeFile } from \"node:fs/promises\";\nimport { relative, resolve } from \"node:path\";\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 * Bun adapter for elur-kit.\n *\n * Produces a self-contained Bun server entry at `.elur/bun-server.ts`.\n * Run it with:\n *\n * bun run .elur/bun-server.ts\n *\n * The server serves static files from `dist/` and renders pages on demand for\n * unmatched routes.\n */\nexport const bunAdapter: Adapter = {\n name: \"bun\",\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 // Verify the production build exists.\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 // Clean previous adapter output.\n await rm(generatedDir, { recursive: true, force: true });\n await mkdir(generatedDir, { recursive: true });\n\n // Scan routes and generate a self-contained SSR handler entry.\n const appDir = resolve(root, options.appDir);\n const routes = await scanRoutes(appDir);\n\n const entryPath = resolve(generatedDir, \"bun-index.ts\");\n await writeSsrEntry(entryPath, routes, options);\n\n // Write the Bun server entry.\n const serverPath = resolve(generatedDir, \"bun-server.ts\");\n await writeFile(\n serverPath,\n buildBunServerSource(relativeToUrlPath(generatedDir, outDir), options),\n \"utf8\",\n );\n },\n};\n\nfunction buildBunServerSource(\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 { fileURLToPath } from \"node:url\";\nimport { createWebHandler } from \"@elurjs/kit/runtime\";\nimport handler from \"./bun-index.ts\";\n\nconst outDir = fileURLToPath(new URL(${JSON.stringify(outDirUrl)}, import.meta.url));\nconst port = Number(process.env.PORT) || ${options.port ?? 3000};\n\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\nBun.serve({\n port,\n async fetch(request) {\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 return response;\n },\n});\n\nconsole.log(\\`Bun server running at http://localhost:\\${port}\\`);\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":";;;;;;AAkBA,IAAa,IAAsB;CACjC,MAAM;CACN,cAAc;CAEd,MAAM,MAAM,GAAS;EACnB,IAAM,IAAO,EAAQ,EAAQ,IAAI,GAC3B,IAAS,EAAQ,GAAM,EAAQ,MAAM,GACrC,IAAe,EAAQ,GAAM,OAAO;EAG1C,IAAI;GACF,MAAM,EAAK,CAAM;EACnB,QAAQ;GACN,MAAU,MACR,+BAA+B,EAAO,8BACxC;EACF;EAIA,AADA,MAAM,EAAG,GAAc;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC,GACvD,MAAM,EAAM,GAAc,EAAE,WAAW,GAAK,CAAC;EAG7C,IAAM,IAAS,EAAQ,GAAM,EAAQ,MAAM,GACrC,IAAS,MAAM,EAAW,CAAM,GAEhC,IAAY,EAAQ,GAAc,cAAc;EACtD,MAAM,EAAc,GAAW,GAAQ,CAAO;EAG9C,IAAM,IAAa,EAAQ,GAAc,eAAe;EACxD,MAAM,EACJ,GACA,EAAqB,EAAkB,GAAc,CAAM,GAAG,CAAO,GACrE,MACF;CACF;AACF;AAEA,SAAS,EACP,GACA,GAKQ;CACR,OAAO;;;;;uCAK8B,KAAK,UAAU,CAAS,EAAE;2CACtB,EAAQ,QAAQ,IAAK;;;;;gCAKhC,KAAK,UAAU,EAAQ,IAAI,EAAE,iBAAiB,KAAK,UAAU,EAAQ,WAAW,EAAE;;;;;;;;;;;;;;;;;;AAkBlH;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":"bun.js","names":[],"sources":["../../../src/adapters/bun.ts"],"sourcesContent":["import { mkdir, rm, stat, writeFile } from \"node:fs/promises\";\nimport { relative, resolve } from \"node:path\";\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 * Bun adapter for elur-kit.\n *\n * Produces a self-contained Bun server entry at `.elur/bun-server.ts`.\n * Run it with:\n *\n * bun run .elur/bun-server.ts\n *\n * The server serves static files from `dist/` and renders pages on demand for\n * unmatched routes.\n */\nexport const bunAdapter: Adapter = {\n name: \"bun\",\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 // Verify the production build exists.\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 // Clean previous adapter output.\n await rm(generatedDir, { recursive: true, force: true });\n await mkdir(generatedDir, { recursive: true });\n\n // Scan routes and generate a self-contained SSR handler entry.\n const appDir = resolve(root, options.appDir);\n const routes = await scanRoutes(appDir);\n\n const entryPath = resolve(generatedDir, \"bun-index.ts\");\n await writeSsrEntry(entryPath, routes, options);\n\n // Write the Bun server entry.\n const serverPath = resolve(generatedDir, \"bun-server.ts\");\n await writeFile(\n serverPath,\n buildBunServerSource(relativeToUrlPath(generatedDir, outDir), options),\n \"utf8\",\n );\n },\n};\n\nfunction buildBunServerSource(\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 { fileURLToPath } from \"node:url\";\nimport { createWebHandler } from \"@elurjs/kit/runtime\";\nimport handler from \"./bun-index.ts\";\n\nconst outDir = fileURLToPath(new URL(${JSON.stringify(outDirUrl)}, import.meta.url));\nconst port = Number(process.env.PORT) || ${options.port ?? 3000};\n\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\nBun.serve({\n port,\n async fetch(request) {\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 return response;\n },\n});\n\nconsole.log(\\`Bun server running at http://localhost:\\${port}\\`);\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":";;;;;;AAkBA,IAAa,IAAsB;CACjC,MAAM;CACN,cAAc;CAEd,MAAM,MAAM,GAAS;EACnB,IAAM,IAAO,EAAQ,EAAQ,IAAI,GAC3B,IAAS,EAAQ,GAAM,EAAQ,MAAM,GACrC,IAAe,EAAQ,GAAM,OAAO;EAG1C,IAAI;GACF,MAAM,EAAK,CAAM;EACnB,QAAQ;GACN,MAAU,MACR,+BAA+B,EAAO,8BACxC;EACF;EAIA,AADA,MAAM,EAAG,GAAc;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC,GACvD,MAAM,EAAM,GAAc,EAAE,WAAW,GAAK,CAAC;EAG7C,IAAM,IAAS,EAAQ,GAAM,EAAQ,MAAM,GACrC,IAAS,MAAM,EAAW,CAAM,GAEhC,IAAY,EAAQ,GAAc,cAAc;EACtD,MAAM,EAAc,GAAW,GAAQ,CAAO;EAG9C,IAAM,IAAa,EAAQ,GAAc,eAAe;EACxD,MAAM,EACJ,GACA,EAAqB,EAAkB,GAAc,CAAM,GAAG,CAAO,GACrE,MACF;CACF;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;;;;;uCAK8B,KAAK,UAAU,CAAS,EAAE;2CACtB,EAAQ,QAAQ,IAAK;;;;;gCAKhC,KAAK,UAAU,EAAQ,IAAI,EAAE,iBAAiB,KAAK,UAAU,EAAQ,WAAW,IAAI,IAAiB,EAAe;;;;;;;;;;;;;;;;;;AAkBpJ;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"}
@@ -18,6 +18,40 @@ export interface AdapterOptions {
18
18
  lang: string;
19
19
  /** Import specifier for hydrateIslands in the generated client entry. */
20
20
  hydrateImport?: string;
21
+ /** Minimum log level for the runtime structured logger. */
22
+ logLevel?: import("../runtime/logger.js").LogLevel;
23
+ /**
24
+ * Pluggable ISR cache adapter (programmatic only). Note: the generated
25
+ * Node/Bun servers cannot serialize adapter instances — they only serve
26
+ * static files and delegate SSR to the bundled handler.
27
+ */
28
+ cacheAdapter?: import("../cache/adapter.js").CacheAdapter;
29
+ /** Redirect rules evaluated before any routing. */
30
+ redirects?: import("../router/redirects.js").RedirectRule[];
31
+ /** Rewrite rules applied transparently before routing. */
32
+ rewrites?: import("../router/redirects.js").RewriteRule[];
33
+ /** Extra response headers applied to matching request paths. */
34
+ routeHeaders?: import("../router/redirects.js").RouteHeadersRule[];
35
+ /**
36
+ * Opt-in streaming SSR (experimental). Baked into the generated server:
37
+ * routes with a `loading` boundary stream shell-first when the adapter
38
+ * declares `capabilities.streaming: true`.
39
+ */
40
+ streaming?: boolean;
41
+ /**
42
+ * Client router flag baked into the generated server. When `enabled` is
43
+ * false the SSR output emits no client scripts and no render-endpoint
44
+ * marker; when a split `/_elur/router.js` chunk exists in the build output
45
+ * it is advertised as the router entry automatically.
46
+ */
47
+ router?: {
48
+ enabled?: boolean;
49
+ };
50
+ /**
51
+ * Client JS mode baked into the generated server. `"legacy"` restores the
52
+ * unconditional single client entry (pre-0%-JS behavior).
53
+ */
54
+ js?: "modern" | "legacy";
21
55
  }
22
56
  /**
23
57
  * An adapter turns a elur-kit build into a deployment target output.
@@ -18,6 +18,40 @@ export interface AdapterOptions {
18
18
  lang: string;
19
19
  /** Import specifier for hydrateIslands in the generated client entry. */
20
20
  hydrateImport?: string;
21
+ /** Minimum log level for the runtime structured logger. */
22
+ logLevel?: import("../runtime/logger.js").LogLevel;
23
+ /**
24
+ * Pluggable ISR cache adapter (programmatic only). Note: the generated
25
+ * Node/Bun servers cannot serialize adapter instances — they only serve
26
+ * static files and delegate SSR to the bundled handler.
27
+ */
28
+ cacheAdapter?: import("../cache/adapter.js").CacheAdapter;
29
+ /** Redirect rules evaluated before any routing. */
30
+ redirects?: import("../router/redirects.js").RedirectRule[];
31
+ /** Rewrite rules applied transparently before routing. */
32
+ rewrites?: import("../router/redirects.js").RewriteRule[];
33
+ /** Extra response headers applied to matching request paths. */
34
+ routeHeaders?: import("../router/redirects.js").RouteHeadersRule[];
35
+ /**
36
+ * Opt-in streaming SSR (experimental). Baked into the generated server:
37
+ * routes with a `loading` boundary stream shell-first when the adapter
38
+ * declares `capabilities.streaming: true`.
39
+ */
40
+ streaming?: boolean;
41
+ /**
42
+ * Client router flag baked into the generated server. When `enabled` is
43
+ * false the SSR output emits no client scripts and no render-endpoint
44
+ * marker; when a split `/_elur/router.js` chunk exists in the build output
45
+ * it is advertised as the router entry automatically.
46
+ */
47
+ router?: {
48
+ enabled?: boolean;
49
+ };
50
+ /**
51
+ * Client JS mode baked into the generated server. `"legacy"` restores the
52
+ * unconditional single client entry (pre-0%-JS behavior).
53
+ */
54
+ js?: "modern" | "legacy";
21
55
  }
22
56
  /**
23
57
  * An adapter turns a elur-kit build into a deployment target output.
@@ -1,4 +1,4 @@
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:`netlify`,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,`netlify`),l=(0,i.join)(c,`functions`),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)(l,{recursive:!0,force:!0}),await(0,r.mkdir)(l,{recursive:!0}),await(0,r.mkdir)(u,{recursive:!0});let d=(0,i.resolve)(o,n.appDir),f=await e.t(d),p=(0,i.resolve)(u,`netlify-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:()=>`__elur-js-kit.mjs`},rollupOptions:{external:[],output:{inlineDynamicImports:!0}}}});let m=(0,i.join)(l,`netlify-index.js`),h=(0,i.join)(l,`__elur-js-kit.mjs`);try{await(0,r.stat)(m),await(0,r.rename)(m,h)}catch{}await(0,r.writeFile)((0,i.join)(o,`netlify.toml`),`[build]
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:`netlify`,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,`netlify`),l=(0,i.join)(c,`functions`),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)(l,{recursive:!0,force:!0}),await(0,r.mkdir)(l,{recursive:!0}),await(0,r.mkdir)(u,{recursive:!0});let d=(0,i.resolve)(o,t.appDir),f=await e.t(d),p=(0,i.resolve)(u,`netlify-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:()=>`__elur-js-kit.mjs`},rollupOptions:{external:[],output:{inlineDynamicImports:!0}}}});let m=(0,i.join)(l,`netlify-index.js`),h=(0,i.join)(l,`__elur-js-kit.mjs`);try{await(0,r.stat)(m),await(0,r.rename)(m,h)}catch{}await(0,r.writeFile)((0,i.join)(o,`netlify.toml`),`[build]
2
2
  command = "elur-kit build"
3
3
  publish = "dist"
4
4
 
@@ -1,15 +1,15 @@
1
1
  import { t as e } from "../route-scanner-XcLId7lK.js";
2
- import { n as t } from "../shared-DU3iQgr7.js";
3
- import { r as n } from "../capabilities-C7txofmY.js";
2
+ import { r as t } from "../capabilities-C7txofmY.js";
3
+ import { n } from "../shared-D8w-neq2.js";
4
4
  import { mkdir as r, rename as i, rm as a, stat as o, writeFile as s } from "node:fs/promises";
5
5
  import { join as c, resolve as l } from "node:path";
6
6
  import { build as u } from "vite";
7
7
  //#region src/adapters/netlify.ts
8
8
  var d = {
9
9
  name: "netlify",
10
- capabilities: n,
11
- async build(n) {
12
- let d = l(n.root), f = l(d, n.outDir), p = l(d, "netlify"), m = c(p, "functions"), h = l(d, ".elur");
10
+ capabilities: t,
11
+ async build(t) {
12
+ let d = l(t.root), f = l(d, t.outDir), p = l(d, "netlify"), m = c(p, "functions"), h = l(d, ".elur");
13
13
  try {
14
14
  await o(f);
15
15
  } catch {
@@ -19,8 +19,8 @@ var d = {
19
19
  recursive: !0,
20
20
  force: !0
21
21
  }), await r(m, { recursive: !0 }), await r(h, { recursive: !0 });
22
- let g = l(d, n.appDir), _ = await e(g), v = l(h, "netlify-index.ts");
23
- await t(v, _, n), await u({
22
+ let g = l(d, t.appDir), _ = await e(g), v = l(h, "netlify-index.ts");
23
+ await n(v, _, t), await u({
24
24
  configFile: !1,
25
25
  root: d,
26
26
  build: {
@@ -1,8 +1,8 @@
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:`node`,capabilities:n.t,async build(n){let o=(0,i.resolve)(n.root),l=(0,i.resolve)(o,n.outDir),u=(0,i.resolve)(o,`.elur`);try{await(0,r.stat)(l)}catch{throw Error(`Output directory not found: ${l}. Run "elur-kit build" first.`)}await(0,r.rm)(u,{recursive:!0,force:!0}),await(0,r.mkdir)(u,{recursive:!0});let d=(0,i.resolve)(o,n.appDir),f=await e.t(d),p=(0,i.resolve)(u,`node-index.ts`);await t.n(p,f,n);let m=(0,i.resolve)(u,`node-server.ts`);await(0,r.writeFile)(m,s(c(u,l),n),`utf8`),await(0,a.build)({configFile:!1,root:o,build:{outDir:u,emptyOutDir:!1,ssr:!0,lib:{entry:m,formats:[`es`]},rollupOptions:{external:[/^@elurjs\/kit(?:\/.*)?$/,/^@elurjs\/core(?:\/.*)?$/,/^node:/],output:{entryFileNames:`node-server.mjs`,inlineDynamicImports:!0}}}})}};function s(e,t){return`// AUTO-GENERATED by @elurjs/kit. Do not edit.
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:`node`,capabilities:t.t,async build(t){let o=(0,i.resolve)(t.root),l=(0,i.resolve)(o,t.outDir),u=(0,i.resolve)(o,`.elur`);try{await(0,r.stat)(l)}catch{throw Error(`Output directory not found: ${l}. Run "elur-kit build" first.`)}await(0,r.rm)(u,{recursive:!0,force:!0}),await(0,r.mkdir)(u,{recursive:!0});let d=(0,i.resolve)(o,t.appDir),f=await e.t(d),p=(0,i.resolve)(u,`node-index.ts`);await n.n(p,f,t);let m=(0,i.resolve)(u,`node-server.ts`);await(0,r.writeFile)(m,s(c(u,l),t),`utf8`),await(0,a.build)({configFile:!1,root:o,build:{outDir:u,emptyOutDir:!1,ssr:!0,lib:{entry:m,formats:[`es`]},rollupOptions:{external:[/^@elurjs\/kit(?:\/.*)?$/,/^@elurjs\/core(?:\/.*)?$/,/^node:/],output:{entryFileNames:`node-server.mjs`,inlineDynamicImports:!0}}}})}};function s(e,t){let n=t.logLevel?`, logLevel: ${JSON.stringify(t.logLevel)}`:``,r=[`redirects`,`rewrites`,`routeHeaders`].map(e=>{let n=t[e];return n&&n.length>0?`, ${e}: ${JSON.stringify(n)}`:``}).join(``);return`// AUTO-GENERATED by @elurjs/kit. Do not edit.
2
2
  import { createServer } from "node:http";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { createWebHandler } from "@elurjs/kit/runtime";
5
- import { incomingMessageToRequest } from "@elurjs/kit/runtime";
5
+ import { incomingMessageToRequest, sendWebResponse } from "@elurjs/kit/runtime";
6
6
  import handler from "./node-index.ts";
7
7
 
8
8
  const outDir = fileURLToPath(new URL(${JSON.stringify(e)}, import.meta.url));
@@ -14,7 +14,7 @@ const port = Number(process.env.PORT) || ${t.port??3e3};
14
14
  const webHandler = createWebHandler(
15
15
  { pages: [], api: [], error404: undefined, error500: undefined },
16
16
  {},
17
- { staticRoot: outDir, lang: ${JSON.stringify(t.lang)}, clientEntry: ${JSON.stringify(t.clientEntry)} },
17
+ { staticRoot: outDir, lang: ${JSON.stringify(t.lang)}, clientEntry: ${JSON.stringify(t.clientEntry)}${n}${r} },
18
18
  );
19
19
 
20
20
  createServer(async (req, res) => {
@@ -28,8 +28,8 @@ createServer(async (req, res) => {
28
28
  if (response.status === 404) {
29
29
  response = await handler(request);
30
30
  }
31
- res.writeHead(response.status, Object.fromEntries(response.headers.entries()));
32
- res.end(Buffer.from(await response.arrayBuffer()));
31
+ // Streams the body: streaming SSR chunks flush as they are produced.
32
+ await sendWebResponse(res, response);
33
33
  }).listen(port, () => {
34
34
  console.log(\`Node server running at http://localhost:\${port}\`);
35
35
  });
@@ -1 +1 @@
1
- {"version":3,"file":"node.cjs","names":[],"sources":["../../../src/adapters/node.ts"],"sourcesContent":["import { mkdir, rm, stat, writeFile } from \"node:fs/promises\";\nimport { relative, resolve } from \"node:path\";\nimport { build } from \"vite\";\nimport { scanRoutes } from \"../router/route-scanner.js\";\nimport type { Adapter } from \"./index.js\";\nimport { writeSsrEntry } from \"./shared.js\";\nimport { DEFAULT_CAPABILITIES } from \"../runtime/capabilities.js\";\n\n/**\n * Node adapter for 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":"6QAmBA,IAAa,EAAuB,CAClC,KAAM,OACN,aAAc,EAAA,EAEd,MAAM,MAAM,EAAS,CACnB,IAAM,GAAA,EAAO,EAAA,QAAA,CAAQ,EAAQ,IAAI,EAC3B,GAAA,EAAS,EAAA,QAAA,CAAQ,EAAM,EAAQ,MAAM,EACrC,GAAA,EAAe,EAAA,QAAA,CAAQ,EAAM,OAAO,EAE1C,GAAI,CACF,MAAA,EAAM,EAAA,KAAA,CAAK,CAAM,CACnB,MAAQ,CACN,MAAU,MACR,+BAA+B,EAAO,8BACxC,CACF,CAEA,MAAA,EAAM,EAAA,GAAA,CAAG,EAAc,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EACvD,MAAA,EAAM,EAAA,MAAA,CAAM,EAAc,CAAE,UAAW,EAAK,CAAC,EAE7C,IAAM,GAAA,EAAS,EAAA,QAAA,CAAQ,EAAM,EAAQ,MAAM,EACrC,EAAS,MAAM,EAAA,EAAW,CAAM,EAEhC,GAAA,EAAY,EAAA,QAAA,CAAQ,EAAc,eAAe,EACvD,MAAM,EAAA,EAAc,EAAW,EAAQ,CAAO,EAE9C,IAAM,GAAA,EAAa,EAAA,QAAA,CAAQ,EAAc,gBAAgB,EACzD,MAAA,EAAM,EAAA,UAAA,CACJ,EACA,EAAsB,EAAkB,EAAc,CAAM,EAAG,CAAO,EACtE,MACF,EAEA,MAAA,EAAM,EAAA,MAAA,CAAM,CACV,WAAY,GACZ,OACA,MAAO,CACL,OAAQ,EACR,YAAa,GACb,IAAK,GACL,IAAK,CACH,MAAO,EACP,QAAS,CAAC,IAAI,CAChB,EACA,cAAe,CACb,SAAU,CAAC,0BAA2B,2BAA4B,QAAQ,EAC1E,OAAQ,CACN,eAAgB,kBAChB,qBAAsB,EACxB,CACF,CACF,CACF,CAAC,CACH,CACF,EAEA,SAAS,EACP,EACA,EAKQ,CACR,MAAO;;;;;;;uCAO8B,KAAK,UAAU,CAAS,EAAE;2CACtB,EAAQ,MAAQ,IAAK;;;;;;;;gCAQhC,KAAK,UAAU,EAAQ,IAAI,EAAE,iBAAiB,KAAK,UAAU,EAAQ,WAAW,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BlH,CAEA,SAAS,EAAkB,EAAc,EAAoB,CAC3D,IAAM,GAAA,EAAO,EAAA,SAAA,CAAS,EAAM,CAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,GAAG,EACpD,MAAO,GAAG,EAAK,WAAW,GAAG,EAAI,EAAO,KAAK,IAAO,EACtD"}
1
+ {"version":3,"file":"node.cjs","names":[],"sources":["../../../src/adapters/node.ts"],"sourcesContent":["import { mkdir, rm, stat, writeFile } from \"node:fs/promises\";\nimport { relative, resolve } from \"node:path\";\nimport { build } from \"vite\";\nimport { scanRoutes } from \"../router/route-scanner.js\";\nimport type { Adapter } from \"./index.js\";\nimport { writeSsrEntry } from \"./shared.js\";\nimport { DEFAULT_CAPABILITIES } from \"../runtime/capabilities.js\";\n\n/**\n * Node adapter for 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":"6QAmBA,IAAa,EAAuB,CAClC,KAAM,OACN,aAAc,EAAA,EAEd,MAAM,MAAM,EAAS,CACnB,IAAM,GAAA,EAAO,EAAA,QAAA,CAAQ,EAAQ,IAAI,EAC3B,GAAA,EAAS,EAAA,QAAA,CAAQ,EAAM,EAAQ,MAAM,EACrC,GAAA,EAAe,EAAA,QAAA,CAAQ,EAAM,OAAO,EAE1C,GAAI,CACF,MAAA,EAAM,EAAA,KAAA,CAAK,CAAM,CACnB,MAAQ,CACN,MAAU,MACR,+BAA+B,EAAO,8BACxC,CACF,CAEA,MAAA,EAAM,EAAA,GAAA,CAAG,EAAc,CAAE,UAAW,GAAM,MAAO,EAAK,CAAC,EACvD,MAAA,EAAM,EAAA,MAAA,CAAM,EAAc,CAAE,UAAW,EAAK,CAAC,EAE7C,IAAM,GAAA,EAAS,EAAA,QAAA,CAAQ,EAAM,EAAQ,MAAM,EACrC,EAAS,MAAM,EAAA,EAAW,CAAM,EAEhC,GAAA,EAAY,EAAA,QAAA,CAAQ,EAAc,eAAe,EACvD,MAAM,EAAA,EAAc,EAAW,EAAQ,CAAO,EAE9C,IAAM,GAAA,EAAa,EAAA,QAAA,CAAQ,EAAc,gBAAgB,EACzD,MAAA,EAAM,EAAA,UAAA,CACJ,EACA,EAAsB,EAAkB,EAAc,CAAM,EAAG,CAAO,EACtE,MACF,EAEA,MAAA,EAAM,EAAA,MAAA,CAAM,CACV,WAAY,GACZ,OACA,MAAO,CACL,OAAQ,EACR,YAAa,GACb,IAAK,GACL,IAAK,CACH,MAAO,EACP,QAAS,CAAC,IAAI,CAChB,EACA,cAAe,CACb,SAAU,CAAC,0BAA2B,2BAA4B,QAAQ,EAC1E,OAAQ,CACN,eAAgB,kBAChB,qBAAsB,EACxB,CACF,CACF,CACF,CAAC,CACH,CACF,EAEA,SAAS,EACP,EACA,EASQ,CACR,IAAM,EAAiB,EAAQ,SAAW,eAAe,KAAK,UAAU,EAAQ,QAAQ,IAAM,GAExF,EAAkB,CAAC,YAAa,WAAY,cAAc,CAAC,CAC9D,IAAK,GAAQ,CACZ,IAAM,EAAQ,EAAQ,GACtB,OAAO,GAAS,EAAM,OAAS,EAAI,KAAK,EAAI,IAAI,KAAK,UAAU,CAAK,IAAM,EAC5E,CAAC,CAAC,CACD,KAAK,EAAE,EACV,MAAO;;;;;;;uCAO8B,KAAK,UAAU,CAAS,EAAE;2CACtB,EAAQ,MAAQ,IAAK;;;;;;;;gCAQhC,KAAK,UAAU,EAAQ,IAAI,EAAE,iBAAiB,KAAK,UAAU,EAAQ,WAAW,IAAI,IAAiB,EAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BpJ,CAEA,SAAS,EAAkB,EAAc,EAAoB,CAC3D,IAAM,GAAA,EAAO,EAAA,SAAA,CAAS,EAAM,CAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,GAAG,EACpD,MAAO,GAAG,EAAK,WAAW,GAAG,EAAI,EAAO,KAAK,IAAO,EACtD"}
@@ -1,15 +1,15 @@
1
1
  import { t as e } from "../route-scanner-XcLId7lK.js";
2
- import { n as t } from "../shared-DU3iQgr7.js";
3
- import { t as n } from "../capabilities-C7txofmY.js";
2
+ import { t } from "../capabilities-C7txofmY.js";
3
+ import { n } from "../shared-D8w-neq2.js";
4
4
  import { mkdir as r, rm as i, stat as a, writeFile as o } from "node:fs/promises";
5
5
  import { relative as s, resolve as c } from "node:path";
6
6
  import { build as l } from "vite";
7
7
  //#region src/adapters/node.ts
8
8
  var u = {
9
9
  name: "node",
10
- capabilities: n,
11
- async build(n) {
12
- let s = c(n.root), u = c(s, n.outDir), p = c(s, ".elur");
10
+ capabilities: t,
11
+ async build(t) {
12
+ let s = c(t.root), u = c(s, t.outDir), p = c(s, ".elur");
13
13
  try {
14
14
  await a(u);
15
15
  } catch {
@@ -19,10 +19,10 @@ var u = {
19
19
  recursive: !0,
20
20
  force: !0
21
21
  }), await r(p, { recursive: !0 });
22
- let m = c(s, n.appDir), h = await e(m), g = c(p, "node-index.ts");
23
- await t(g, h, n);
22
+ let m = c(s, t.appDir), h = await e(m), g = c(p, "node-index.ts");
23
+ await n(g, h, t);
24
24
  let _ = c(p, "node-server.ts");
25
- await o(_, d(f(p, u), n), "utf8"), await l({
25
+ await o(_, d(f(p, u), t), "utf8"), await l({
26
26
  configFile: !1,
27
27
  root: s,
28
28
  build: {
@@ -49,11 +49,19 @@ var u = {
49
49
  }
50
50
  };
51
51
  function d(e, t) {
52
+ let n = t.logLevel ? `, logLevel: ${JSON.stringify(t.logLevel)}` : "", r = [
53
+ "redirects",
54
+ "rewrites",
55
+ "routeHeaders"
56
+ ].map((e) => {
57
+ let n = t[e];
58
+ return n && n.length > 0 ? `, ${e}: ${JSON.stringify(n)}` : "";
59
+ }).join("");
52
60
  return `// AUTO-GENERATED by @elurjs/kit. Do not edit.
53
61
  import { createServer } from "node:http";
54
62
  import { fileURLToPath } from "node:url";
55
63
  import { createWebHandler } from "@elurjs/kit/runtime";
56
- import { incomingMessageToRequest } from "@elurjs/kit/runtime";
64
+ import { incomingMessageToRequest, sendWebResponse } from "@elurjs/kit/runtime";
57
65
  import handler from "./node-index.ts";
58
66
 
59
67
  const outDir = fileURLToPath(new URL(${JSON.stringify(e)}, import.meta.url));
@@ -65,7 +73,7 @@ const port = Number(process.env.PORT) || ${t.port ?? 3e3};
65
73
  const webHandler = createWebHandler(
66
74
  { pages: [], api: [], error404: undefined, error500: undefined },
67
75
  {},
68
- { staticRoot: outDir, lang: ${JSON.stringify(t.lang)}, clientEntry: ${JSON.stringify(t.clientEntry)} },
76
+ { staticRoot: outDir, lang: ${JSON.stringify(t.lang)}, clientEntry: ${JSON.stringify(t.clientEntry)}${n}${r} },
69
77
  );
70
78
 
71
79
  createServer(async (req, res) => {
@@ -79,8 +87,8 @@ createServer(async (req, res) => {
79
87
  if (response.status === 404) {
80
88
  response = await handler(request);
81
89
  }
82
- res.writeHead(response.status, Object.fromEntries(response.headers.entries()));
83
- res.end(Buffer.from(await response.arrayBuffer()));
90
+ // Streams the body: streaming SSR chunks flush as they are produced.
91
+ await sendWebResponse(res, response);
84
92
  }).listen(port, () => {
85
93
  console.log(\`Node server running at http://localhost:\${port}\`);
86
94
  });