@elurjs/kit 2.4.4

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 (255) hide show
  1. package/CHANGELOG.md +874 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1330 -0
  4. package/bin/elur-kit.js +54 -0
  5. package/dist/lib/action/define.d.cts +72 -0
  6. package/dist/lib/action/define.d.ts +72 -0
  7. package/dist/lib/action/error-store.d.cts +29 -0
  8. package/dist/lib/action/error-store.d.ts +29 -0
  9. package/dist/lib/action/index.cjs +1 -0
  10. package/dist/lib/action/index.d.cts +64 -0
  11. package/dist/lib/action/index.d.ts +64 -0
  12. package/dist/lib/action/index.js +2 -0
  13. package/dist/lib/action/origin.d.cts +20 -0
  14. package/dist/lib/action/origin.d.ts +20 -0
  15. package/dist/lib/action/scan.d.cts +28 -0
  16. package/dist/lib/action/scan.d.ts +28 -0
  17. package/dist/lib/action/server.d.cts +30 -0
  18. package/dist/lib/action/server.d.ts +30 -0
  19. package/dist/lib/action-BB6N5yD-.js +111 -0
  20. package/dist/lib/action-BB6N5yD-.js.map +1 -0
  21. package/dist/lib/action-DZHihU3Z.cjs +2 -0
  22. package/dist/lib/action-DZHihU3Z.cjs.map +1 -0
  23. package/dist/lib/adapters/bun.cjs +30 -0
  24. package/dist/lib/adapters/bun.cjs.map +1 -0
  25. package/dist/lib/adapters/bun.d.cts +13 -0
  26. package/dist/lib/adapters/bun.d.ts +13 -0
  27. package/dist/lib/adapters/bun.js +65 -0
  28. package/dist/lib/adapters/bun.js.map +1 -0
  29. package/dist/lib/adapters/index.cjs +0 -0
  30. package/dist/lib/adapters/index.d.cts +30 -0
  31. package/dist/lib/adapters/index.d.ts +30 -0
  32. package/dist/lib/adapters/index.js +0 -0
  33. package/dist/lib/adapters/netlify.cjs +10 -0
  34. package/dist/lib/adapters/netlify.cjs.map +1 -0
  35. package/dist/lib/adapters/netlify.d.cts +13 -0
  36. package/dist/lib/adapters/netlify.d.ts +13 -0
  37. package/dist/lib/adapters/netlify.js +51 -0
  38. package/dist/lib/adapters/netlify.js.map +1 -0
  39. package/dist/lib/adapters/node.cjs +46 -0
  40. package/dist/lib/adapters/node.cjs.map +1 -0
  41. package/dist/lib/adapters/node.d.cts +13 -0
  42. package/dist/lib/adapters/node.d.ts +13 -0
  43. package/dist/lib/adapters/node.js +105 -0
  44. package/dist/lib/adapters/node.js.map +1 -0
  45. package/dist/lib/adapters/shared.d.cts +17 -0
  46. package/dist/lib/adapters/shared.d.ts +17 -0
  47. package/dist/lib/adapters/vercel.cjs +2 -0
  48. package/dist/lib/adapters/vercel.cjs.map +1 -0
  49. package/dist/lib/adapters/vercel.d.cts +9 -0
  50. package/dist/lib/adapters/vercel.d.ts +9 -0
  51. package/dist/lib/adapters/vercel.js +62 -0
  52. package/dist/lib/adapters/vercel.js.map +1 -0
  53. package/dist/lib/build/build.d.cts +83 -0
  54. package/dist/lib/build/build.d.ts +83 -0
  55. package/dist/lib/build/document-shell.d.cts +48 -0
  56. package/dist/lib/build/document-shell.d.ts +48 -0
  57. package/dist/lib/build/transform-source.d.cts +26 -0
  58. package/dist/lib/build/transform-source.d.ts +26 -0
  59. package/dist/lib/build/vite-build.d.cts +78 -0
  60. package/dist/lib/build/vite-build.d.ts +78 -0
  61. package/dist/lib/cache/policy.d.cts +25 -0
  62. package/dist/lib/cache/policy.d.ts +25 -0
  63. package/dist/lib/cache.d.cts +13 -0
  64. package/dist/lib/cache.d.ts +13 -0
  65. package/dist/lib/capabilities-C0TDQoMY.cjs +2 -0
  66. package/dist/lib/capabilities-C0TDQoMY.cjs.map +1 -0
  67. package/dist/lib/capabilities-C7txofmY.js +45 -0
  68. package/dist/lib/capabilities-C7txofmY.js.map +1 -0
  69. package/dist/lib/cli/commands.d.cts +15 -0
  70. package/dist/lib/cli/commands.d.ts +15 -0
  71. package/dist/lib/cli.cjs +5132 -0
  72. package/dist/lib/cli.cjs.map +1 -0
  73. package/dist/lib/cli.d.cts +30 -0
  74. package/dist/lib/cli.d.ts +30 -0
  75. package/dist/lib/cli.js +5131 -0
  76. package/dist/lib/cli.js.map +1 -0
  77. package/dist/lib/collections-Dbc8aRLf.js +233 -0
  78. package/dist/lib/collections-Dbc8aRLf.js.map +1 -0
  79. package/dist/lib/collections-VDy5g9p8.cjs +13 -0
  80. package/dist/lib/collections-VDy5g9p8.cjs.map +1 -0
  81. package/dist/lib/config/index.cjs +2 -0
  82. package/dist/lib/config/index.cjs.map +1 -0
  83. package/dist/lib/config/index.d.cts +100 -0
  84. package/dist/lib/config/index.d.ts +100 -0
  85. package/dist/lib/config/index.js +122 -0
  86. package/dist/lib/config/index.js.map +1 -0
  87. package/dist/lib/content/collections.d.cts +69 -0
  88. package/dist/lib/content/collections.d.ts +69 -0
  89. package/dist/lib/content/frontmatter.d.cts +20 -0
  90. package/dist/lib/content/frontmatter.d.ts +20 -0
  91. package/dist/lib/content/index.cjs +2 -0
  92. package/dist/lib/content/index.cjs.map +1 -0
  93. package/dist/lib/content/index.d.cts +5 -0
  94. package/dist/lib/content/index.d.ts +5 -0
  95. package/dist/lib/content/index.js +28 -0
  96. package/dist/lib/content/index.js.map +1 -0
  97. package/dist/lib/content/markdown.d.cts +6 -0
  98. package/dist/lib/content/markdown.d.ts +6 -0
  99. package/dist/lib/content/raw.d.cts +9 -0
  100. package/dist/lib/content/raw.d.ts +9 -0
  101. package/dist/lib/content/schema.d.cts +14 -0
  102. package/dist/lib/content/schema.d.ts +14 -0
  103. package/dist/lib/errors-0X7pCFNU.cjs +2 -0
  104. package/dist/lib/errors-0X7pCFNU.cjs.map +1 -0
  105. package/dist/lib/errors-ePYxDlhU.js +70 -0
  106. package/dist/lib/errors-ePYxDlhU.js.map +1 -0
  107. package/dist/lib/errors.d.cts +84 -0
  108. package/dist/lib/errors.d.ts +84 -0
  109. package/dist/lib/hydrate-8a3TbQbs.cjs +2 -0
  110. package/dist/lib/hydrate-8a3TbQbs.cjs.map +1 -0
  111. package/dist/lib/hydrate-CgZGrTxF.js +126 -0
  112. package/dist/lib/hydrate-CgZGrTxF.js.map +1 -0
  113. package/dist/lib/image/index.cjs +2 -0
  114. package/dist/lib/image/index.cjs.map +1 -0
  115. package/dist/lib/image/index.d.cts +37 -0
  116. package/dist/lib/image/index.d.ts +37 -0
  117. package/dist/lib/image/index.js +49 -0
  118. package/dist/lib/image/index.js.map +1 -0
  119. package/dist/lib/image/pipeline.d.cts +37 -0
  120. package/dist/lib/image/pipeline.d.ts +37 -0
  121. package/dist/lib/image/registry.cjs +2 -0
  122. package/dist/lib/image/registry.cjs.map +1 -0
  123. package/dist/lib/image/registry.d.cts +26 -0
  124. package/dist/lib/image/registry.d.ts +26 -0
  125. package/dist/lib/image/registry.js +23 -0
  126. package/dist/lib/image/registry.js.map +1 -0
  127. package/dist/lib/image/service.cjs +2 -0
  128. package/dist/lib/image/service.cjs.map +1 -0
  129. package/dist/lib/image/service.d.cts +164 -0
  130. package/dist/lib/image/service.d.ts +164 -0
  131. package/dist/lib/image/service.js +308 -0
  132. package/dist/lib/image/service.js.map +1 -0
  133. package/dist/lib/index.cjs +1 -0
  134. package/dist/lib/index.cjs.map +1 -0
  135. package/dist/lib/index.d.cts +38 -0
  136. package/dist/lib/index.d.ts +38 -0
  137. package/dist/lib/index.js +1 -0
  138. package/dist/lib/index.js.map +1 -0
  139. package/dist/lib/integrations/hooks.d.cts +58 -0
  140. package/dist/lib/integrations/hooks.d.ts +58 -0
  141. package/dist/lib/integrations/index.cjs +1 -0
  142. package/dist/lib/integrations/index.d.cts +18 -0
  143. package/dist/lib/integrations/index.d.ts +18 -0
  144. package/dist/lib/integrations/index.js +2 -0
  145. package/dist/lib/integrations-7dpN1RYB.js +35 -0
  146. package/dist/lib/integrations-7dpN1RYB.js.map +1 -0
  147. package/dist/lib/integrations-DDqfWjvH.cjs +2 -0
  148. package/dist/lib/integrations-DDqfWjvH.cjs.map +1 -0
  149. package/dist/lib/interpolation-plugin-Bt-KRKVY.js +365 -0
  150. package/dist/lib/interpolation-plugin-Bt-KRKVY.js.map +1 -0
  151. package/dist/lib/interpolation-plugin-CMPCDlVJ.cjs +31 -0
  152. package/dist/lib/interpolation-plugin-CMPCDlVJ.cjs.map +1 -0
  153. package/dist/lib/island/generate-entry.d.cts +27 -0
  154. package/dist/lib/island/generate-entry.d.ts +27 -0
  155. package/dist/lib/island/hydrate.d.cts +33 -0
  156. package/dist/lib/island/hydrate.d.ts +33 -0
  157. package/dist/lib/island/index.cjs +1 -0
  158. package/dist/lib/island/index.d.cts +2 -0
  159. package/dist/lib/island/index.d.ts +2 -0
  160. package/dist/lib/island/index.js +1 -0
  161. package/dist/lib/island/island.d.cts +32 -0
  162. package/dist/lib/island/island.d.ts +32 -0
  163. package/dist/lib/island/scan.d.cts +14 -0
  164. package/dist/lib/island/scan.d.ts +14 -0
  165. package/dist/lib/manifest/index.cjs +3 -0
  166. package/dist/lib/manifest/index.cjs.map +1 -0
  167. package/dist/lib/manifest/index.d.cts +18 -0
  168. package/dist/lib/manifest/index.d.ts +18 -0
  169. package/dist/lib/manifest/index.js +110 -0
  170. package/dist/lib/manifest/index.js.map +1 -0
  171. package/dist/lib/middleware/index.d.cts +56 -0
  172. package/dist/lib/middleware/index.d.ts +56 -0
  173. package/dist/lib/middleware/stream-boundary.d.cts +53 -0
  174. package/dist/lib/middleware/stream-boundary.d.ts +53 -0
  175. package/dist/lib/node-http-DRAUhO0c.js +617 -0
  176. package/dist/lib/node-http-DRAUhO0c.js.map +1 -0
  177. package/dist/lib/node-http-DhxguYyz.cjs +13 -0
  178. package/dist/lib/node-http-DhxguYyz.cjs.map +1 -0
  179. package/dist/lib/render/render-to-string.d.cts +12 -0
  180. package/dist/lib/render/render-to-string.d.ts +12 -0
  181. package/dist/lib/render/ssr-flag.d.cts +4 -0
  182. package/dist/lib/render/ssr-flag.d.ts +4 -0
  183. package/dist/lib/route-scanner-JY6YrNH5.cjs +2 -0
  184. package/dist/lib/route-scanner-JY6YrNH5.cjs.map +1 -0
  185. package/dist/lib/route-scanner-XcLId7lK.js +100 -0
  186. package/dist/lib/route-scanner-XcLId7lK.js.map +1 -0
  187. package/dist/lib/router/client.cjs +2 -0
  188. package/dist/lib/router/client.cjs.map +1 -0
  189. package/dist/lib/router/client.d.cts +47 -0
  190. package/dist/lib/router/client.d.ts +47 -0
  191. package/dist/lib/router/client.js +298 -0
  192. package/dist/lib/router/client.js.map +1 -0
  193. package/dist/lib/router/route-scanner.d.cts +50 -0
  194. package/dist/lib/router/route-scanner.d.ts +50 -0
  195. package/dist/lib/runtime/capabilities.d.cts +47 -0
  196. package/dist/lib/runtime/capabilities.d.ts +47 -0
  197. package/dist/lib/runtime/context.d.cts +140 -0
  198. package/dist/lib/runtime/context.d.ts +140 -0
  199. package/dist/lib/runtime/handler.d.cts +39 -0
  200. package/dist/lib/runtime/handler.d.ts +39 -0
  201. package/dist/lib/runtime/index.cjs +1 -0
  202. package/dist/lib/runtime/index.d.cts +6 -0
  203. package/dist/lib/runtime/index.d.ts +6 -0
  204. package/dist/lib/runtime/index.js +4 -0
  205. package/dist/lib/runtime/node-http.d.cts +2 -0
  206. package/dist/lib/runtime/node-http.d.ts +2 -0
  207. package/dist/lib/runtime/security-headers.d.cts +13 -0
  208. package/dist/lib/runtime/security-headers.d.ts +13 -0
  209. package/dist/lib/runtime/static.d.cts +1 -0
  210. package/dist/lib/runtime/static.d.ts +1 -0
  211. package/dist/lib/runtime-CrH5X-Es.cjs +2 -0
  212. package/dist/lib/runtime-CrH5X-Es.cjs.map +1 -0
  213. package/dist/lib/runtime-Ds2-wH6P.js +520 -0
  214. package/dist/lib/runtime-Ds2-wH6P.js.map +1 -0
  215. package/dist/lib/scan-CY2O9ty6.cjs +2 -0
  216. package/dist/lib/scan-CY2O9ty6.cjs.map +1 -0
  217. package/dist/lib/scan-CjMUgnsd.js +22 -0
  218. package/dist/lib/scan-CjMUgnsd.js.map +1 -0
  219. package/dist/lib/scan-DXzYtmRQ.cjs +2 -0
  220. package/dist/lib/scan-DXzYtmRQ.cjs.map +1 -0
  221. package/dist/lib/scan-Dn93ycXG.js +33 -0
  222. package/dist/lib/scan-Dn93ycXG.js.map +1 -0
  223. package/dist/lib/seo/index.cjs +10 -0
  224. package/dist/lib/seo/index.cjs.map +1 -0
  225. package/dist/lib/seo/index.d.cts +99 -0
  226. package/dist/lib/seo/index.d.ts +99 -0
  227. package/dist/lib/seo/index.js +41 -0
  228. package/dist/lib/seo/index.js.map +1 -0
  229. package/dist/lib/shared-CfqOLsKj.cjs +183 -0
  230. package/dist/lib/shared-CfqOLsKj.cjs.map +1 -0
  231. package/dist/lib/shared-DU3iQgr7.js +236 -0
  232. package/dist/lib/shared-DU3iQgr7.js.map +1 -0
  233. package/dist/lib/ssr/match.d.cts +25 -0
  234. package/dist/lib/ssr/match.d.ts +25 -0
  235. package/dist/lib/ssr/render.d.cts +62 -0
  236. package/dist/lib/ssr/render.d.ts +62 -0
  237. package/dist/lib/ssr/server.d.cts +41 -0
  238. package/dist/lib/ssr/server.d.ts +41 -0
  239. package/dist/lib/ssr/stream.d.cts +48 -0
  240. package/dist/lib/ssr/stream.d.ts +48 -0
  241. package/dist/lib/stream-CpOG052V.js +104 -0
  242. package/dist/lib/stream-CpOG052V.js.map +1 -0
  243. package/dist/lib/stream-DmZjYqHm.cjs +17 -0
  244. package/dist/lib/stream-DmZjYqHm.cjs.map +1 -0
  245. package/dist/lib/types.d.cts +97 -0
  246. package/dist/lib/types.d.ts +97 -0
  247. package/dist/lib/vite/index.cjs +2 -0
  248. package/dist/lib/vite/index.cjs.map +1 -0
  249. package/dist/lib/vite/index.d.cts +41 -0
  250. package/dist/lib/vite/index.d.ts +41 -0
  251. package/dist/lib/vite/index.js +229 -0
  252. package/dist/lib/vite/index.js.map +1 -0
  253. package/dist/lib/vite/interpolation-plugin.d.cts +64 -0
  254. package/dist/lib/vite/interpolation-plugin.d.ts +64 -0
  255. package/package.json +292 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,874 @@
1
+ # Changelog
2
+
3
+ All notable changes to Nix.js Kit are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [2.4.4]
9
+
10
+ ### Fixed
11
+
12
+ - **`island()` directive `"only"` never hydrated on the client** — v2.4.3
13
+ added `"only"` to the SSR side (skip rendering) but the client hydrator
14
+ (`hydrateIslands`) only had branches for `"load"`, `"idle"`, and
15
+ `"visible"`. Markers with `data-directive="only"` were silently skipped
16
+ — the component never mounted, leaving the fallback HTML (or empty
17
+ marker) permanently. Now `"only"` hydrates immediately like `"load"`.
18
+ - **`hydrateTemplate` did nothing for islands without SSR DOM** —
19
+ `hydrateTemplate` from the core walks existing DOM for hydration
20
+ markers (`<!--nix-N-->`, `data-nix-e-*`). Islands with `"only"` or
21
+ `ssr: false` have no SSR DOM in the marker (only fallback HTML or
22
+ nothing), so `hydrateTemplate` either silently did nothing (templates
23
+ with no bindings) or threw a mismatch and remounted (templates with
24
+ bindings). The hydrator now detects the absence of `<!--nix-` markers
25
+ and does a fresh `_render` mount instead of `hydrateTemplate`, which
26
+ is the correct operation when there's no SSR DOM to hydrate against.
27
+ This also fixes the same issue for `ssr: false` with any directive.
28
+
29
+ ## [2.4.3]
30
+
31
+ ### Fixed
32
+
33
+ - **`island()` crashed for client-only components after happy-dom removal**
34
+ — since v2.4.0 removed the happy-dom SSR fallback, `island()` always
35
+ executed the component during SSR. Any island accessing browser-only
36
+ globals (`document`, `window`, `navigator`, ...) in its body crashed with
37
+ `ReferenceError: document is not defined`, breaking carousels, charts, and
38
+ any third-party widget that touches the DOM. The kit now provides two
39
+ opt-out mechanisms mirroring the industry standard (Astro `client:only`,
40
+ Next.js `dynamic(..., { ssr: false })`):
41
+ - `directive: "only"` — shortcut for client-only with `load` scheduling.
42
+ The component is never called during SSR; only the fallback is rendered.
43
+ - `options: { ssr: false }` — client-only with any directive
44
+ (`load`/`idle`/`visible`), combinable with `options.fallback`.
45
+ SSR errors are never silently swallowed: they propagate wrapped with the
46
+ island name and three concrete remediation paths (`"only"`, `{ ssr: false }`,
47
+ `isSSR()`), matching Astro and Next.js behavior.
48
+
49
+ ### Added
50
+
51
+ - **`IslandOptions`** — new optional 5th parameter to `island()` with:
52
+ - `ssr?: boolean` (default `true`, forced `false` when `directive: "only"`)
53
+ - `fallback?: NixTemplate | string` — HTML rendered inside the island
54
+ marker when SSR is skipped or the component returns `null`/`false`.
55
+ Accepts a reactive `NixTemplate` (with signals) or a plain string.
56
+ - **`island()` `fallback` for null components** — when an SSR-safe component
57
+ returns `null`/`false`/`undefined`, the `fallback` option is now rendered
58
+ instead of an empty marker.
59
+ - **`isSSR()` exported from the main entry** — reads the Nix.js reactivity
60
+ SSR flag. Use it to guard environment reads (`window.matchMedia`,
61
+ `localStorage`, `navigator`) in SSR-safe components. Note: `isSSR()` is
62
+ NOT a replacement for `"only"`/`ssr: false` — it cannot make
63
+ `document.querySelectorAll` of the component's own children work, because
64
+ the DOM is not inserted when the function body runs. For DOM queries of
65
+ own children, use `NixComponent.onMount()` + `ref`.
66
+ - **`IslandDirective` now includes `"only"`** — the type union is
67
+ `"load" | "idle" | "visible" | "only"`. The duplicate type definition in
68
+ `hydrate.ts` was replaced with a re-export from `island.ts` for a single
69
+ source of truth.
70
+
71
+ ## [2.4.2]
72
+
73
+ ### Fixed
74
+
75
+ - **`BuildResult.outDir`** — added `outDir` field to `BuildResult` so
76
+ integration `build` hooks know the actual output directory (the atomic
77
+ staging temp dir when called via the CLI, not the final `dist/`).
78
+ Without this, integrations that wrote to `join(context.root, "dist")`
79
+ had their artifacts wiped by the atomic staging commit. Now integrations
80
+ can use `result.outDir` to write to the correct directory.
81
+
82
+ ## [2.4.1]
83
+
84
+ ### Fixed
85
+
86
+ - **Integration `build` hook never invoked** — the `build` hook was
87
+ declared in `NixKitIntegration` but never called from `build()`.
88
+ `runIntegrationHook` was only wired for `"config"` (from
89
+ `config/index.ts`) and `"routes"` (from `manifest/index.ts`). Now
90
+ `build()` invokes `runIntegrationHook(integrations, "build", [result,
91
+ ctx])` at the end of the build pipeline, after all pages, image
92
+ variants, and the manifest are written. This lets integrations
93
+ generate post-build artifacts (sitemaps, robots.txt, search indexes)
94
+ into the output directory. The hook fires before the CLI's atomic
95
+ staging commit, so integration artifacts survive the swap.
96
+ - **`BuildConfig.integrations`** — new optional field. The CLI's
97
+ `toBuildConfig()` now passes `resolvedConfig.integrations` through.
98
+
99
+ ## [2.4.0]
100
+
101
+ ### Fixed
102
+
103
+ - **CLI bundling bug — image registry dual instance** — the CLI bundle
104
+ (`dist/lib/cli.js`) was inlining its own copy of the image registry
105
+ (`renderRegistry`, `activeManifest`), separate from the chunk
106
+ `dist/lib/image/index.js` that user pages import. This caused
107
+ `consumeImageRegistry()` to always return `[]`, so the two-pass image
108
+ pipeline silently processed nothing (no manifest, no variants, no
109
+ `<picture>`). Fixed by extracting the registry state to a dedicated
110
+ chunk `src/image/registry.ts` and externalizing it in
111
+ `vite.cli.config.ts` via a custom plugin, so the CLI imports the same
112
+ physical `./image/registry.js` chunk that `image/index.js` uses.
113
+ - **`raw()` missing `renderServer`** — after removing the happy-dom
114
+ fallback, the core's DOM-free `renderToString` requires templates to
115
+ expose `NIX_RENDER_PROTOCOL.renderServer`. `raw()` only had `mount`
116
+ and `_render` (DOM-dependent), causing "Template does not support
117
+ server rendering" errors. Fixed by adding `renderServer: () => html`
118
+ to `raw()`, matching the pattern already used by `image()` and
119
+ `island()`.
120
+ - **Streaming response test mocks** — updated mock templates in
121
+ `test/streaming-response.test.ts` to use `renderServer` instead of
122
+ DOM-dependent `_render`, and removed an invalid `supportsStreaming({})`
123
+ call that didn't match the `Pick<AdapterCapabilities, "streaming">`
124
+ parameter type.
125
+
126
+ ### Changed
127
+
128
+ - **`happy-dom` fully removed** — the kit no longer references happy-dom
129
+ anywhere. The SSR runtime uses the core's DOM-free `renderToString`
130
+ (`@deijose/nix-js/server`) directly, with no DOM fallback. Removed
131
+ from `peerDependenciesMeta`, from both vite build configs
132
+ (`external`/`globals`), and from `src/render/render-to-string.ts`
133
+ (the `renderWithDom` fallback and `MANAGED_GLOBALS` injection were
134
+ deleted). The `test/happy-dom-optional.test.ts` now asserts happy-dom
135
+ is absent from all dependency fields.
136
+ - **Config file renamed: `nix.config.*` → `nix-js.config.*`** — the
137
+ generic `nix.config.ts` name was a design error that could collide
138
+ with other tools. The kit now looks for `nix-js.config.{ts,js,mjs}`
139
+ first. Legacy `nix.config.*` files are still detected for backward
140
+ compatibility, but emit a deprecation warning guiding migration.
141
+ `doDoctor` reports legacy config files as `warn` status.
142
+
143
+ ### Added
144
+
145
+ - **`src/image/registry.ts`** — new shared singleton module owning the
146
+ image pipeline's mutable state (`renderRegistry`, `activeManifest`).
147
+ Exported as `dist/lib/image/registry.js` and added to
148
+ `tsconfig.lib.json` and `vite.lib.config.ts` entry points. Both the
149
+ CLI bundle and the library chunk import this physical file, ensuring
150
+ a single module instance across the build pipeline.
151
+
152
+ ## [2.3.0]
153
+
154
+ ### Changed
155
+
156
+ - **Interpolation now delegates to the Vite plugin** — when
157
+ `@deijose/vite-plugin-nix-js` >= 1.1.0 is installed, the kit's legacy
158
+ interpolation transform is skipped (the plugin's state-machine lexer takes
159
+ precedence). The kit's transform remains as a fallback for projects that
160
+ use the kit without the plugin.
161
+ - New `pluginSupportsPartialInterpolation()` function detects the Vite plugin
162
+ at runtime.
163
+ - `shouldUseLegacyInterpolation("auto")` now returns `false` when the plugin
164
+ is installed, `true` when neither the plugin nor the core supports partials.
165
+ - `@deijose/vite-plugin-nix-js` added as an optional peer dependency.
166
+
167
+ ### Migration
168
+
169
+ - Install `@deijose/vite-plugin-nix-js` >= 1.1.0 for the best interpolation
170
+ support (state-machine lexer, compile-time errors, raw-text tag handling).
171
+ - The kit's legacy transform still works without the plugin but is less
172
+ powerful (no comment/raw-text handling, no boolean attr validation).
173
+
174
+ ## [2.2.1]
175
+
176
+ ### Changed
177
+
178
+ - `coreSupportsPartialInterpolation()` and `shouldUseLegacyInterpolation()`
179
+ are now exported from `@deijose/nix-js-kit/vite` so consumers can resolve
180
+ the interpolation mode programmatically.
181
+
182
+ ## [2.2.0]
183
+
184
+ ### Changed
185
+
186
+ - **Native partial attribute interpolation** — when the installed Nix.js core
187
+ exposes `templateFeatures.partialAttributeInterpolation` (core ≥ 3.3), the
188
+ kit no longer injects the legacy `nixJsInterpolationPlugin` transform
189
+ (`interpolation: "auto"`). Partial attributes now run through the runtime's
190
+ native normalization, which preserves fine-grained reactivity instead of
191
+ collapsing getters into a static concatenation.
192
+ - New `interpolation: "auto" | "legacy" | "off"` option on `nixJsKit()`,
193
+ `buildClientBundle()` and `transformProjectFiles()`.
194
+ - `interpolation: "legacy"` forces the old transform for migrations and
195
+ emits a one-time deprecation warning; `interpolation: "off"` disables it.
196
+ - `transformPartialInterpolations` stays exported for direct consumers and
197
+ is marked deprecated.
198
+
199
+ ## [2.1.0]
200
+
201
+ ### Added — five reported limitations fixed
202
+
203
+ - **#1: Route-level code-splitting** — the generated client entry already uses
204
+ `import()` per island, producing separate chunks per page for a minimal
205
+ initial bundle. Documented and verified with tests.
206
+ - **#2: Layout Slots** — `*.slot.ts` files are now detected by the route
207
+ scanner and passed to layout components as named slots (`slots.sidebar`,
208
+ `slots.header`, etc.). Route groups (`(group)`) already worked; this adds
209
+ named slot composition on top.
210
+ - **#3: Redis / Upstash / Cloudflare KV cache adapters** — new
211
+ `createRedisCacheAdapter()` and `createCloudflareKVCacheAdapter()` in
212
+ `@deijose/nix-js-kit/cache`, implementing the same `CacheAdapter` interface
213
+ as the filesystem adapter. Tag-based invalidation works via Redis sets or
214
+ KV JSON indexes.
215
+ - **#4: Real Suspense streaming** — `streamBoundary()` and
216
+ `createStreamingResponse()` now emit a `<template>` chunk + replacement
217
+ script that swaps the fallback `<div>` for the resolved content in-place
218
+ (using `replaceWith`), instead of the old `innerHTML` append pattern.
219
+ New helpers: `buildFallbackHtml()`, `buildResolvedChunk()`.
220
+
221
+ ### Changed
222
+
223
+ - **#5: `happy-dom` moved to optional peer dependency** — removed from
224
+ `dependencies`, added to `peerDependenciesMeta` with `optional: true`.
225
+ The SSR runtime loads it via dynamic `import("happy-dom")` only when the
226
+ core renderer needs a DOM fallback; it is never bundled into client code.
227
+
228
+ ## [2.0.4]
229
+
230
+ ### Added — recursive content collections
231
+
232
+ - `getCollection()` now scans nested directories and derives nested slugs
233
+ (e.g. `getting-started/intro`), removing the need for manual content scanners.
234
+
235
+ ## [2.0.3]
236
+
237
+ ### Added — island HMR (Vite plugin)
238
+
239
+ - The generated client entry now registers `import.meta.hot.accept` so island
240
+ module changes are **hot-swapped without a full page reload**: current islands
241
+ are disposed and re-hydrated from the updated modules (audit §10.2 / §12.2).
242
+ - New E2E in `example/e2e/hmr.spec.ts` (Playwright + Vite plugin dev server)
243
+ verifies the DOM updates with `performance navigation` count unchanged.
244
+ - Script: `npm run test:e2e:hmr`.
245
+
246
+ ## [2.0.2]
247
+
248
+ ### Fixed — compliance and correctness (audit §8–§10)
249
+
250
+ - **Unified CLI request pipeline** — `handleRequest` (dev/preview) now delegates
251
+ to `createWebHandler`, the same code used by the Node/Bun/Vercel/Netlify
252
+ adapters. The duplicated actions/render-endpoint/API/static/SSR/404/500
253
+ pipeline in `src/cli.ts` was removed (audit §8.1, Risk 1).
254
+ - **`start` with missing middleware (Bun)** — `loadMiddleware` matched
255
+ "module not found" via `err instanceof Error`, but Bun's `ResolveMessage` is
256
+ not an `Error` instance, so projects without `src/middleware.ts` failed to
257
+ start. Detection now uses the message property directly.
258
+ - **Stale content after server actions under SSR** — the `start` server and the
259
+ unified handler rewrite the baked `nix-js:render-endpoint content="off"` meta
260
+ to `"on"` when serving static HTML, so SPA navigations after a mutating
261
+ action fetch live server-rendered content instead of the stale static file
262
+ (fixes e.g. "review published without reload").
263
+ - **Stale core bundled in the CLI** — `vite.cli.config.ts` externalizes
264
+ `@deijose/nix-js/*` (including subpaths) so the CLI never bundles an
265
+ outdated copy of the core server renderer.
266
+ - **Island loader detection without probing** — the registry now uses a
267
+ discriminated `{ load }` lazy form plus `AsyncFunction` detection (never
268
+ invoking the component as a probe, avoiding side effects / duplicate signal
269
+ creation). New `lazyIsland()` helper (audit §10.3).
270
+ - **Production error sanitization** — new `toPublicErrorInfo()` /
271
+ `publicErrorResponse()` in `src/errors.ts`; the unified handler, action
272
+ server and adapters no longer expose `String(err)` (paths/stacks/secrets) in
273
+ responses (audit §8.4, Risk 5).
274
+
275
+ ### Added — static serving, images and capabilities
276
+
277
+ - **Static serving Range/If-Range/HEAD** — `serveStaticFile` now supports
278
+ `Accept-Ranges`, single `Range` with `If-Range` (ETag or date), `206` with
279
+ `Content-Range`, `416` for unsatisfiable ranges, and uniform HEAD responses
280
+ (audit §8.3).
281
+ - **Image pipeline hardening** — SHA-256 transform keys (content + normalized
282
+ options + encoder/naming versions), path containment for sources and outputs
283
+ (no traversal/NUL/symlink escape), atomic temp+rename writes, single-flight
284
+ per transform key, bounded concurrency pool, and `images.strict` build mode
285
+ (audit §9.4–§9.7).
286
+ - **`getImage()` and `ImageService`** — programmatic async image API and the
287
+ `ImageService`/`createImageService` contract with declared capabilities
288
+ (audit §9.2–§9.3).
289
+ - **Adapter capability contract** — `AdapterCapabilities` (streaming,
290
+ filesystem none/readonly/persistent/ephemeral, imageRuntime, backgroundWork,
291
+ maxBodySize), defaults for full/serverless/edge hosts, and build-time
292
+ `validateCapabilities()` diagnostics in the CLI `adapter` command
293
+ (audit §8.5).
294
+
295
+ ### Test
296
+
297
+ - New suites: static range/HEAD (10), error sanitization (6), image hardening
298
+ (12), capabilities (10), cross-runtime parity (3), island lazy-loader
299
+ detection (3). Full suite at 442 tests (was 398). Fixed pre-existing failing
300
+ tests: island entry generator (`require` in ESM), benchmark variance
301
+ threshold, and the router clear-cookie test (happy-dom does not honor
302
+ `Max-Age=0` removal).
303
+
304
+ ### Docs
305
+
306
+ - README: streaming labelled experimental; static serving now documents
307
+ Range/HEAD. See `docs/nix-js-kit/` for the full remediation record.
308
+
309
+ ## [2.1.x] — v2 development
310
+
311
+ ### Fixed — v2.0.1 patch: hydration and asset serving
312
+
313
+ - **SSR hydration markers** — `renderToString` in `src/render/render-to-string.ts` now passes `markers: "hydration"` to the core `renderServer` by default. Previously it omitted the option, so the SSR output had no `<!--nix-N-->` comments or `data-nix-e-*`/`data-nix-a-*` attributes, causing `[nix-js] Hydration marker mismatch: Template has no hydration descriptor` on every island.
314
+ - **Island async loader detection** — `src/island/hydrate.ts` detected lazy loaders via `entry.constructor?.name === "AsyncFunction"`, but `() => import(...).then(m => m.default)` is a regular function returning a Promise, not an `AsyncFunction`. This caused `e._render is not a function` because the loader function was passed directly to `hydrateTemplate` instead of being awaited. Fixed by probing the entry and checking `result instanceof Promise`.
315
+ - **Client bundle base path** — `buildClientBundle` in `src/cli.ts` used `base: "/"` by default, so Vite's modulepreload helper generated URLs like `/assets/ThemeToggle.js` instead of `/_nix-js/assets/ThemeToggle.js`, causing 404s for all island chunks. Fixed by hardcoding `base: "/_nix-js/"` for the client bundle (independent of the project's deployment `base`).
316
+ - **Test assertions updated** — integration, render, preview, and adapter tests now strip `<!--nix-N-->` / `<!--nix-end-N-->` hydration markers before content assertions, since SSR output now includes them by default.
317
+
318
+ ### Added — Phase 13: Verification, packaging, audit, benchmarks
319
+
320
+ - **Package smoke test** — `test/package-smoke.test.ts` validates tarball creation, ESM/CJS entry imports, CLI binary, exports map, Node engine, and tarball contents (no src/test/scripts leaked).
321
+ - **Path traversal fuzz tests** — `test/path-traversal-fuzz.test.ts` (20 tests) covers encoded traversal (`%2e%2e`, `%2f`, `%5c`), mixed separators, NUL bytes, Unicode normalization (U+FF0E, U+FF0F), prefix-sibling paths, and symlink escape (A-06).
322
+ - **CSRF cross-origin tests** — `test/csrf-origin.test.ts` (19 tests) covers same-origin, cross-origin, missing headers, `strictOrigin` mode, allow-list, invalid headers, non-HTTP protocols, and `Sec-Fetch-Site` (A-07).
323
+ - **Cache concurrency + isolation tests** — `test/cache-concurrency.test.ts` (13 tests) covers single-flight deduplication, stale-while-revalidate, private/public isolation (cookies, Authorization, no-store), atomicity, collision resistance, and tag invalidation (A-08).
324
+ - **SSR benchmark baseline** — `test/benchmark-ssr.test.ts` measures `renderToString` throughput (126,940 renders/sec on the test machine) with a budget floor of 500 renders/sec for regression detection.
325
+ - **RequestContext tests** — `test/request-context.test.ts` (17 tests) verifies per-request state: `params`, `locals` isolation, `cookies` (read/write), `signal`, `requestId` uniqueness, `platform`, `response` state, and `applyToResponse()` merging.
326
+ - **`bun audit`** — zero vulnerabilities after lockfile cleanup (A-24).
327
+ - **`publint`** — `All good!` after splitting `types` conditions into `import`/`require` and adding `.d.cts` declaration copies.
328
+ - **Pendientes documentados** — `docs/nix-js-kit/pendientes-infraestructura.md` lista los items que requieren infraestructura externa (Playwright E2E, CI matrix, Provenance/SBOM, `arethetypeswrong`, examples, Lighthouse).
329
+
330
+ ### Changed — Phase 13
331
+
332
+ - **`RequestContext` aligned with runtime-security §4** — added `params`, `locals`, `cookies` (CookieJar), `signal` (AbortSignal), `requestId` (auto-generated UUID), `platform`, `route`, and `response` (ResponseState with mutable headers and ResponseCookieJar). New `applyToResponse()` method merges accumulated headers, Set-Cookie values, and status into the final Response. New types: `CookieJar`, `ResponseCookieJar`, `CookieOptions`, `ResponseState`.
333
+ - **`handleApiRoute`** now passes `locals` alongside `params` to API route handlers.
334
+ - **`src/runtime/index.ts`** exports the new cookie and response types.
335
+ - **`defineAction`** and related types now exported from `src/index.ts` (main entry).
336
+
337
+ ### Added — Phase 10: Actions, middleware, cookies, cache/ISR
338
+
339
+ - **`defineAction()`** — typed server action definition with input validation (`.parse()`), AbortSignal propagation, idempotency metadata, and concurrency modes (`latest`, `queue`, `parallel`). Legacy action exports preserved.
340
+ - **`CacheAdapter`** — filesystem cache with SHA-256 identity keys, atomic temp+rename writes, single-flight per process, stale-while-revalidate (`getWithSWR()`), tag-based invalidation, size limits and periodic cleanup.
341
+ - **Cache policy per route** — `CachePolicy` with `public`/`private`/`dynamic` modes, `normalizeCachePolicy()` reads `export const cache` from data modules, `shouldCachePublic()` enforces no public caching for requests with cookies/auth/action-state.
342
+ - **Middleware propagation** — `next()` now carries `params` and `locals`, cleanup callbacks executed in `finally`, `loadMiddleware()` distinguishes "file not found" from "file has errors".
343
+ - **Cache invalidation hub** — `CacheInvalidator` pub/sub with `connectCacheAdapter()`, `defaultInvalidator` singleton. Actions emit tags/paths; cache listens. No coupling to `nix-query`.
344
+
345
+ ### Added — Phase 11: Streaming, routing, content, SEO, integrations
346
+
347
+ - **Real streaming** — `createStreamingResponse()` with `ReadableStream` that sends shell + loading fallback, then resolved content chunks with deterministic IDs. `createBufferedResponse()` for adapters without streaming. `streamBoundary` uses `AsyncLocalStorage` per-request.
348
+ - **Optional catch-all** — `[[...slug]]` route segments that match the base path and any depth.
349
+ - **Route conflict detection** — `scanRoutes()` throws on duplicate path patterns during manifest generation.
350
+ - **Safe URL decoding** — `safeDecodeURIComponent()` handles malformed percent-encoding without throwing.
351
+ - **Redirects/rewrites/route headers** — `matchRedirect()`, `matchRewrite()`, `matchRouteHeaders()` with `:param` and `*` wildcard support.
352
+ - **Sitemap from route manifest** — `generateSitemapFromRoutes()` excludes dynamic/API/error routes, supports `extraUrls` for dynamic routes, splits into sitemap index for >50,000 URLs.
353
+ - **Content scope per request** — `withContentRoot()` via `AsyncLocalStorage`, cache key includes root, collection name containment validation (no path traversal).
354
+ - **Integration hooks** — typed registry for `I18nIntegration`, `AuthIntegration`, `QueryIntegration`, `TestingIntegration` + custom integrations. Optional packages register without being dependencies.
355
+
356
+ ### Added — Phase 12: DX, scaffold, observability
357
+
358
+ - **CLI commands** — `check` (typecheck + route/config integrity), `routes` (list all discovered routes), `doctor` (diagnose common issues).
359
+ - **Structured logger** — `StructuredLogger` with request ID generation, `Server-Timing` header accumulation, sensitive data redaction (cookies, auth headers), structured JSON output in production.
360
+ - **Error messages** — `formatError()` with cause/path/suggestion format, reliable exit codes (`ExitCode`).
361
+ - **create-nix-app template** — `template-kit` with config, public, islands, content, tests, adapter-ready scripts.
362
+
363
+ ### Security hardening (Phase 10)
364
+
365
+ - JSON-LD escapes `<`, `>`, `&`, U+2028, U+2029 to prevent script injection (A-19).
366
+ - Action error cookies signed with HMAC SHA-256 (A-20).
367
+ - Body limits enforced with stream reading and `413` responses (§8.2).
368
+ - Default security headers: `X-Content-Type-Options`, `Referrer-Policy`, `X-Frame-Options`, CSP with nonce support, HSTS when appropriate, Permissions-Policy.
369
+ - Static serving with `ETag`/`If-None-Match`, `Last-Modified`/`If-Modified-Since`, immutable caching for hashed assets.
370
+ - `throw new Response()` treated as first-class HTTP control flow from loaders and layout loaders (A-22).
371
+ - No public caching of responses with `Set-Cookie`, `private`, or `no-store`.
372
+
373
+ ---
374
+
375
+ ## [1.x] — Release history
376
+
377
+ ## 1.4.8
378
+
379
+ ### Added
380
+
381
+ - **Full Open Graph image metadata** — `OpenGraphMetadata` now supports `imageAlt`, `imageWidth`, `imageHeight`, and `imageType`, emitted as `og:image:alt`, `og:image:width`, `og:image:height`, and `og:image:type`. `TwitterMetadata` gained `imageAlt` (`twitter:image:alt`). Social scrapers (Twitter/X, LinkedIn, iMessage, WhatsApp) use these tags to render share previews reliably.
382
+
383
+ ## 1.4.7
384
+
385
+ ### Fixed
386
+
387
+ - **No more 404 storms on static deployments** — static builds now emit `<meta name="nix-js:render-endpoint" content="off">` in the HTML `<head>`, so the client router skips the `/__nix-js/render` endpoint entirely (zero 404 requests). For older builds without the marker, endpoint detection now uses a single shared probe promise — concurrent prefetches generate at most **one** request to the endpoint, and any other failed page falls back to HTML fetching without disabling the endpoint globally.
388
+
389
+ ### Changed
390
+
391
+ - **Prefetch is now interaction-only by default (Astro-style)** — the router prefetches internal pages on hover/focus instead of prefetching every visible link on load. This removes the post-load burst of page fetches that competed with fonts and images for bandwidth on slow connections. Links can opt back into viewport prefetching with `data-prefetch="viewport"`.
392
+
393
+ ### Added
394
+
395
+ - **`renderEndpoint` build option** — `BuildConfig.renderEndpoint` (default `true`) controls whether the built HTML announces the render endpoint as available. The SSG `build()` passes `renderEndpoint: false` automatically; dev/preview/SSR servers leave it enabled.
396
+
397
+ ## 1.4.6
398
+
399
+ ### Fixed
400
+
401
+ - **SPA router now works on static deployments** — when the `/__nix-js/render` endpoint is unavailable (Vercel static, Netlify static, GitHub Pages), the router falls back to fetching the full HTML page and extracting `#app` + `<head>` tags. This enables SPA navigation without a server, matching the dev-mode experience.
402
+
403
+ ## 1.4.5
404
+
405
+ ### Added
406
+
407
+ - **`headLinks` support in data loaders** — loaders can now return a `headLinks: string[]` array of raw HTML strings (e.g. `<link rel="icon">`, `<link rel="manifest">`, `<meta name="theme-color">`) that are injected directly into `<head>`, alongside the existing `headScripts`. Deduplicated across layout and page data.
408
+
409
+ ## 1.4.4
410
+
411
+ ### Fixed
412
+
413
+ - **Removed dependency on `_setSSR` from `@deijose/nix-js`** — the published 2.6.0 on npm does not export `_setSSR`/`_isSSR`. The kit now manipulates the reactivity state's `ssr` flag directly via a local `setSSR()` utility in `src/render/ssr-flag.ts`. This fixes the Vercel build error: `SyntaxError: Export named '_setSSR' not found`.
414
+
415
+ ## 1.4.3
416
+
417
+ ### Fixed
418
+
419
+ - **Pinned `@deijose/nix-js` to 2.6.0** — fixed a build error on Vercel where `^2.5.3` resolved to a newer version that no longer exports `_setSSR`.
420
+
421
+ ## 1.4.2
422
+
423
+ ### Fixed
424
+
425
+ - **Hash link navigation** — the SPA router now handles `#anchor` links with smooth scroll instead of ignoring them or reloading the page.
426
+ - **Scrollable element preservation** — elements marked with `data-scroll-preserve="key"` have their scroll position saved and restored across SPA navigations, preventing sidebar scroll resets.
427
+
428
+ ## 1.4.1
429
+
430
+ ### Fixed
431
+
432
+ - **JSON-LD in headScripts** — `documentShell` now detects when a `headScript` is already a complete `<script>` tag (e.g. `<script type="application/ld+json">...`) and renders it as-is instead of wrapping it in another `<script>` tag.
433
+
434
+ ## 1.4.0
435
+
436
+ ### Added
437
+
438
+ - **SEO module** (`@deijose/nix-js-kit/seo`) — sitemap.xml, robots.txt, and JSON-LD structured data generation:
439
+ - `generateSitemap({ siteUrl, urls, outDir })` writes a valid `sitemap.xml` from a list of URL entries (supports `lastmod`, `changefreq`, `priority`).
440
+ - `generateRobots({ siteUrl, outDir, rules?, disallow? })` writes a `robots.txt` with per-user-agent rules and automatic sitemap reference.
441
+ - `jsonLd(schema)` serializes Schema.org structured data into a `<script type="application/ld+json">` tag for rich snippets.
442
+ - Full TypeScript types for all config objects.
443
+
444
+ ## 1.3.1
445
+
446
+ ### Fixed
447
+
448
+ - **SPA router FOUC fix** — stylesheets (`<link rel="stylesheet">`) and `<style>` tags rendered inside `#app` by layouts are now hoisted to `<head>` on page load and before every SPA navigation, preventing flash-of-unstyled-content on route changes.
449
+ - **`headScripts` deduplication** — `collectShellExtras()` now deduplicates `headScripts` from page and layout data, preventing duplicate inline scripts (e.g. anti-flash theme scripts) when both layers emit the same script.
450
+
451
+ ## 1.3.0
452
+
453
+ ### Added
454
+
455
+ - **CSRF protection for server actions** — `verifyOrigin()` checks the `Origin`/`Referer` header against the `Host` header with optional `allowedOrigins` and `strictOrigin` mode. Configured via `actionSecurity` in the Vite plugin and SSR server options.
456
+ - **Action error cookie store** — action failure data is now stored in an ephemeral `__nix_js_action_error` cookie (SameSite=Lax, Max-Age=15s) instead of URL query parameters, improving security and privacy. `props.form` is populated from the cookie and cleared on the next response.
457
+ - **Metadata API** — pages can export `generateMetadata(context)` or return a `metadata` field from loaders/layouts. Supports `title`, `description`, `canonical`, `openGraph`, `twitter`, `robots`, and `other` fields. Head tags are marked with `data-nix-js-head` for SPA head merge.
458
+ - **Head merge in SPA router** — the client router swaps `<head>` tags marked with `data-nix-js-head` on every navigation, keeping metadata in sync with the current page.
459
+ - **Scroll restoration** — the client router saves and restores scroll position per path on `popstate`, so back/forward navigation feels native.
460
+ - **Content layer** (`@deijose/nix-js-kit/content`) — typed Markdown collections with YAML frontmatter:
461
+ - `defineCollection({ schema })` for typed frontmatter validation (optional `zod` peer dep).
462
+ - `getCollection(name)`, `getEntry(collection, slug)`, `getEntries(collection, slugs)` for querying content.
463
+ - `renderEntryHTML(entry)` renders Markdown to HTML via `marked` (optional peer dep).
464
+ - Built-in YAML frontmatter parser (strings, numbers, booleans, dates, inline/block arrays) — zero dependencies.
465
+ - `raw(html)` helper for injecting trusted HTML without escaping (e.g. rendered Markdown).
466
+ - HMR for `.md` files in the Vite dev server.
467
+ - `src/content/config.ts` convention for collection definitions.
468
+ - **Image optimization** (`@deijose/nix-js-kit/image`):
469
+ - `image()` helper emits responsive `<img>` with `srcset`, `sizes`, `loading="lazy"`, `decoding="async"`, `fetchpriority`, and `width`/`height` to prevent CLS.
470
+ - Build-time pipeline with `sharp` (optional peer dep) generates WebP/AVIF variants at multiple widths with content-based hashing.
471
+ - `processImages()` API for programmatic access; integrated into `build()` via `consumeImageRegistry()`.
472
+ - `BuildConfig.publicDir` and `BuildConfig.imageFormats` options; `BuildResult.imagesProcessed` reports variant count.
473
+ - **Link prefetch** — the client router prefetches pages on viewport intersection (IntersectionObserver) and on hover/focus, with a 30s TTL cache. Respects `data-no-prefetch` attribute on individual links.
474
+ - **View Transitions API** — the client router uses `document.startViewTransition()` for smooth page transitions when available, with automatic `prefers-reduced-motion` respect.
475
+ - **Middleware** — `src/middleware.ts` convention with `config.matcher` for path filtering. Supports `:param` and `:param*` patterns. Return a `Response` to short-circuit (redirect, 401, etc.) or call `next()` to continue. Integrated into SSR server and Vite plugin.
476
+ - **Stream boundary** (experimental) — `streamBoundary()` wraps a promise with a loading fallback for out-of-order streaming during SSR.
477
+
478
+ ### Changed
479
+
480
+ - Action error data moved from URL query params to ephemeral cookies (`__nix_js_action_error`) for security and privacy.
481
+ - Head tags use `data-nix-js-head` attribute (was `data-nix-head` internally) for consistent `nix-js` naming.
482
+ - `BuildResult` now includes `imagesProcessed` count.
483
+ - `SsrServerOptions` includes `actionSecurity` for CSRF configuration.
484
+ - `NixJsKitViteOptions` includes `actionSecurity`, `contentDir` for content layer root.
485
+ - TypeScript upgraded to 7.0.2 (native Go compiler, 10x faster builds). `baseUrl` removed from `tsconfig.json` (deprecated in TS 7); `paths` now resolve relative to the config file.
486
+ - `marked`, `zod`, and `sharp` added as optional peer dependencies via `peerDependenciesMeta`.
487
+
488
+ ## 1.2.7
489
+
490
+ ### Changed
491
+
492
+ - All identifiers now use the `nix-js` / `nixJs` naming consistently. Public API: `nixAction` is now `nixJsAction` (and the `NixAction` interface is `NixJsAction`). Form protocol fields are now `__nix_js_action_name`, `__nix_js_action_page`, `__nix_js_action_failure`, `__nix_js_action_redirect` and `__nix_js_action_error`; island DOM markers use `__nix_js_island_dispose`. The default document title is `Nix.js Kit App`.
493
+
494
+ ## 1.2.6
495
+
496
+ ### Added
497
+
498
+ - `fail()` and `redirect()` now accept both argument orders (`fail(400, data)` or `fail(data, 400)`, `redirect(303, "/x")` or `redirect("/x")`) and are detected via marker fields, so they work even when the CLI/adapters are bundled separately from the user's action modules.
499
+ - Source transform (`transformProjectFiles`) mirrors the project layout and compensates relative imports that escape the mirrored tree, so apps importing outside `src/` (e.g. the kit's own example) build correctly.
500
+ - Vite plugin now serves the `/__nix-js/render` endpoint (HTML or JSON) used by the SPA router and streaming boundaries.
501
+ - ISR now also caches the `/__nix-js/render` endpoint, so streamed pages (with `loading.ts`) regenerate on their `revalidate` TTL instead of being skipped.
502
+ - Data loaders (page and layouts) can return a top-level `htmlAttributes` object to set attributes on the `<html>` element of the document shell (e.g. `{ "data-theme": "dark" }`), applied in SSG, SSR and streaming shells — useful for themes persisted via cookie that must survive redirects.
503
+ - Data loaders can also return `headScripts: string[]`: inline scripts injected into `<head>` that run synchronously before the first paint and before the deferred client bundle. This is the standard no-flash bootstrap (e.g. applying a stored theme to static pages whose SSG shell was baked with the build-time theme).
504
+ - The client router now exports `navigateTo(pathname, search, push)`: a programmatic SPA navigation that fetches the fresh page body from `/__nix-js/render`, swaps `#app`, updates the title and re-hydrates islands. Server actions can use it after a redirect to show fresh server data (e.g. a new review) without a full reload that would serve a stale static page.
505
+
506
+ ### Fixed
507
+
508
+ - CLI bin re-executes itself under the Bun runtime for bun-managed projects, so apps using `bun:sqlite` work with `nix-js-kit build/dev/start/preview`.
509
+ - Attribute interpolation plugin: rewritten with a proper template scanner. Handles nested braces/strings in expressions, single-quoted attributes, comments, and leaves full-value quoted interpolations (`datetime="${x}"`) and unquoted bindings (`value=${() => x}`) untouched.
510
+ - Streaming shells now fetch the concrete path (`/blog/:slug` → `/blog/hello-world`) instead of the route pattern.
511
+ - Client router now requests JSON (`{ title, body }`) from the render endpoint (titles update on SPA navigation), preserves query strings, and ignores modifier-key clicks.
512
+ - Island `data-props` serialization escapes single quotes, so props containing apostrophes hydrate correctly.
513
+ - Declaration files are emitted with explicit `.js` extensions, fixing type resolution for NodeNext consumers; the main entry no longer re-exports the CLI or the Vite plugin (use `@deijose/nix-js-kit/cli` / `@deijose/nix-js-kit/vite`), removing the CLI side-effect from adapter bundles.
514
+ - Adapters: the SSR entry now embeds the full route table (no runtime filesystem scanning), includes `layout.data.ts` modules in the registry, fixes action resolution by page scope, preserves the query string for page rendering, and serves the `/__nix-js/render` endpoint (HTML or JSON) so the SPA router and streaming keep working in production. Works with Node (`node:sqlite`) and Bun (`bun:sqlite`) runtimes.
515
+ - SSR page rendering now forwards the request query string as `searchParams` to loaders.
516
+ - Cookies are forwarded to API routes and server actions in every server mode, so auth/middleware that reads the session works in `start`, `preview`, `dev` and the Vite plugin.
517
+ - Server actions scoped to dynamic routes now work: the resolver maps concrete page paths (`/movies/inception`) to their route pattern (`/movies/:slug`) in `start`, `preview`, `dev`, the Vite plugin and all adapters.
518
+ - The client hydration bundle is now built through a wrapped Vite config that automatically injects the attribute-interpolation plugin, so partial interpolations inside islands (e.g. `href="/movies/${slug}"`) hydrate correctly instead of producing broken attributes.
519
+ - `preview` now renders the custom 404/500 error pages instead of plain-text responses.
520
+ - The `/__nix-js/render` endpoint returns a clean 404 (instead of a 500 with a stack trace) when the requested path has no matching route, in every server mode and in the adapters.
521
+ - Dev server (`nix-js-kit dev`) now runs the actual server in a child process supervised by a watcher: any source change restarts the worker, so page/loader/layout/island edits are always served (previously the ESM module cache served stale modules). Atomic saves (sed/editors) are detected via `rename` events.
522
+ - The dev supervisor exits on SIGTERM so stale processes cannot hold the port.
523
+
524
+ ## 1.2.5
525
+
526
+ ### Added
527
+
528
+ - `layout.data.ts` support: `renderPage` now resolves the nearest `layout.data.ts` loader for each `layout.ts` and passes the returned data to the layout component.
529
+ - Data loaders (page and layout) now receive the current `Request` object in their context, enabling SSR auth, cookies, and per-request headers.
530
+ - Streaming and SSR servers forward the request to both static and streaming render paths so loaders can read session cookies.
531
+
532
+ ### Changed
533
+
534
+ - `LayoutProps` data is now populated from `layout.data.ts` when present; `PageProps` retains the `layoutData` slot for future nested layout support.
535
+
536
+ ## 1.2.4
537
+
538
+ ### Fixed
539
+
540
+ - Client router now re-hydrates islands after navigating to a new page. The generated client entry listens for the `nix-js:rendered` event and mounts islands over the swapped page body.
541
+ - Hydration no longer flashes the static markup: it renders the live island into a `DocumentFragment` and swaps the entire island content with `replaceChildren` in one DOM operation.
542
+ - Old island effects are disposed before the client router swaps `#app.innerHTML`, preventing leaked effects and stale DOM writes after SPA navigation.
543
+ - Vite interpolation plugin rewrites partial attribute interpolations (e.g. `href="/blog/${slug}"`) into a single interpolation in both `src/app` and `src/islands` files during the source transformation step.
544
+
545
+ ## 1.2.3
546
+
547
+ ### Fixed
548
+
549
+ - Dynamic API routes (`[slug]/route.ts`) now receive route parameters as a second argument (`{ params }`) in `nix-js-kit start`, `preview` and `dev`, matching the behavior already documented for API routes.
550
+
551
+ ## 1.2.2
552
+
553
+ ### Changed
554
+
555
+ - Server action registry serialized in the HTML shell now exposes only action names per page (`{"/contact":["subscribe"]}`), never file paths or implementation details.
556
+ - Client router is no longer inlined in every HTML page. It is bundled into the generated client entry (`/_nix-js/entry-client.js`) via `startClientRouter()` from `@deijose/nix-js-kit/router`, so routing code lives in the JS bundle like other frameworks.
557
+
558
+ ## 1.2.1
559
+
560
+ ### Fixed
561
+
562
+ - Server action file paths serialized in the HTML shell (`<script id="nix-js-actions">`) are now relative to the project root instead of absolute server paths. This prevents leaking the host file system layout (e.g. `/home/user/...`) in production HTML.
563
+
564
+ ## 1.2.0
565
+
566
+ ### Added
567
+
568
+ - Vite interpolation plugin transforms partial attribute interpolations (`href="/blog/${slug}"`) into single Nix.js interpolations automatically.
569
+ - Source transformation runs before build/dev/start/preview so authors can write natural `href` attributes without manual workarounds.
570
+ - Inline client-side router in the HTML shell: intercepts internal link clicks, fetches page body from `/__nix-js/render`, swaps `#app` and updates `history.pushState`.
571
+ - `preview` server falls back to on-demand SSR for routes that do not exist in the static `dist/` (e.g. dynamic slugs).
572
+ - Client hydration bundle is built automatically when a `vite.client.config.ts` exists.
573
+
574
+ ## 1.1.1
575
+
576
+ ### Added
577
+
578
+ - Streaming `loading.ts` boundaries: shell renders loading UI and client fetches real content from `/__nix-js/render`.
579
+ - `renderStreamingPage` and `renderPageBody` helpers exported.
580
+ - `streaming` option for `createSsrServer` (defaults to true when a page has `loading.ts`).
581
+
582
+ ## 1.1.0
583
+
584
+ ### Added
585
+
586
+ - ISR (Incremental Static Regeneration) with disk-based cache.
587
+ - `revalidate` export support in `page.data.ts`.
588
+ - `cacheDir` and `defaultRevalidate` options for `createSsrServer` and `nix-js-kit start`.
589
+ - Cache helpers exported: `getCachedHtml`, `setCachedHtml`, `clearCache`.
590
+ - `renderPage` now returns `{ html, revalidate? }`.
591
+
592
+ ## 1.0.0
593
+
594
+ ### Added
595
+
596
+ - Official v1.0 release. The framework is now stable with full test coverage.
597
+ - All v1.0 roadmap items completed: unit and integration tests, HMR, automatic `PageProps<typeof load>` typing, `nixJsAction`, scoped actions, progressive enhancement, `fail()`/`redirect()`, `route.ts` API endpoints, and `loading.ts` boundary scanning.
598
+
599
+ ## 0.11.7
600
+
601
+ ### Added
602
+
603
+ - `fail()` and `redirect()` helpers for server actions with client-side detection in `callAction`/`nixJsAction`.
604
+ - `route.ts` API endpoints supported in SSR server, Vite dev server, CLI preview/dev, and all adapters.
605
+ - `loading.ts` boundary scanned and included in the SSR module registry.
606
+ - `matchApiRoute` helper exported for dispatching API routes.
607
+ - Tests for `fail()`/`redirect()`, API routes, and loading boundaries.
608
+
609
+ ## 0.11.6
610
+
611
+ ### Added
612
+
613
+ - Integration test for the preview server (`doPreview`): serves static files and handles server actions.
614
+ - `doPreview` now returns the Node `http.Server` instance for easier programmatic control and testing.
615
+
616
+ ## 0.11.5
617
+
618
+ ### Added
619
+
620
+ - Integration tests for Vercel and Netlify adapters: build handlers and verify SSR responses.
621
+ - Integration test for Bun adapter: build server entry and verify it serves SSR with `bun run`.
622
+ - Cleanup hooks for Vercel/Netlify/Bun adapter tests.
623
+
624
+ ## 0.11.4
625
+
626
+ ### Added
627
+
628
+ - Integration tests for static build + SSR server.
629
+ - Node adapter integration test: builds `.nix-js/node-server.mjs` and verifies it serves SSR pages.
630
+ - Unit tests for `nixJsAction` helper (pending, data, and error signals).
631
+ - Cleanup hooks for integration tests to remove temporary `dist/` and `.nix-js/` folders.
632
+
633
+ ## 0.11.3
634
+
635
+ ### Added
636
+
637
+ - Initial test suite using Node's built-in test runner (`node:test`) and `tsx` for TypeScript imports.
638
+ - Tests for `scanRoutes`, `scanActions`, `handleActionRequest` (JSON and form), and `renderPage`.
639
+ - `test/fixtures/minimal` with sample pages, data loaders, actions, layout, and a dynamic route.
640
+ - `npm test` and `npm run test:watch` scripts.
641
+
642
+ ## 0.11.2
643
+
644
+ ### Added
645
+
646
+ - `PageProps<typeof load>` and `LayoutProps<typeof load>` now automatically infer the loader's return type (with `Awaited` for async functions).
647
+ - README quick example and dynamic route example use `PageProps<typeof load>`.
648
+ - Example home page uses `PageProps<typeof load>` instead of a manually exported interface.
649
+
650
+ ## 0.11.1
651
+
652
+ ### Added
653
+
654
+ - HMR for routes, actions, loaders, and islands in the Vite dev plugin.
655
+ - Vite dev plugin now resolves actions via `ssrLoadModule` so changed `page.action.ts` files are reloaded without a server restart.
656
+
657
+ ## 0.11.0
658
+
659
+ ### Added
660
+
661
+ - `nixJsAction` helper in `@deijose/nix-js-kit/action` with reactive `pending`, `error`, and `data` signals.
662
+ - Per-page action scoping: `scanActions` now returns `ActionRegistry` keyed by page URL path.
663
+ - `callAction` accepts an optional `{ page }` option to resolve actions scoped to a specific route.
664
+ - Progressive enhancement: `POST /__nix-js/actions` also accepts HTML form submissions and redirects back when `Accept: application/json` is missing.
665
+
666
+ ### Changed
667
+
668
+ - Action registry serialized in `<script id="nix-js-actions">` is now grouped by page path.
669
+ - All action resolvers (SSR server, CLI dev/preview, Vite plugin, adapters) resolve by page first, then fall back to a global search.
670
+ - `callAction` signature updated to `callAction(name, args, options?)` where `args` can be a single value or an array.
671
+ - `callAction` now sends `Accept: application/json` so the server returns JSON instead of a redirect.
672
+ - SSR server, CLI dev/preview, and Vite plugin now forward `Content-Type`, `Accept`, and `Referer` headers to the action handler for correct JSON/form negotiation and redirects.
673
+ - README updated with `nixJsAction`, scoped actions, and progressive enhancement examples.
674
+
675
+ ## 0.10.0
676
+
677
+ ### Added
678
+
679
+ - Node adapter: `nix-js-kit adapter node` generates a self-contained `.nix-js/node-server.mjs` that serves `dist/` static files and renders pages on demand.
680
+ - New subpath export `@deijose/nix-js-kit/adapters/node`.
681
+ - Custom error pages: `src/app/404.page.ts` and `src/app/500.page.ts` are rendered for 404/500 responses during SSG, SSR, and in all deployment adapters.
682
+ - `renderErrorPage()` and `RenderErrorPageOptions` exported from `@deijose/nix-js-kit`.
683
+
684
+ ### Changed
685
+
686
+ - CLI `adapter` command now accepts `vercel`, `netlify`, `bun`, and `node`.
687
+ - Route scanner detects `404.page.ts` and `500.page.ts` files and adds `error404`/`error500` to `ScannedRoutes`.
688
+ - Static build writes `dist/404.html` and `dist/500.html` when error pages are present.
689
+ - README updated with Node adapter and error pages sections.
690
+
691
+ ## 0.9.0
692
+
693
+ ### Added
694
+
695
+ - Server actions: create `page.action.ts` files next to `page.ts` and call exported functions from the client with `callAction()`.
696
+ - New client subpath export `@deijose/nix-js-kit/action` exporting `callAction()` and `ActionRequest`.
697
+ - Server-side action endpoint `POST /__nix-js/actions` handled by the CLI (`dev`, `preview`, `start`), the Vite plugin, and all deployment adapters (Vercel, Netlify, Bun).
698
+ - New server exports `handleActionRequest`, `ActionResolver` and `scanActions` for custom integrations.
699
+ - Document shell now serializes the scanned action registry into `<script id="nix-js-actions">` for client reference.
700
+ - Island hydration markers renamed from `data-nix-island` to `data-nix-js-island`.
701
+
702
+ ### Changed
703
+
704
+ - Route scanner detects `page.action.ts` files and adds `actionPath` to `PageRoute`.
705
+ - README updated with a Server actions section and project conventions tree.
706
+
707
+ ## 0.8.1
708
+
709
+ ### Added
710
+
711
+ - Bun adapter: `nix-js-kit adapter bun` generates `.nix-js/bun-server.ts` and `.nix-js/bun-index.ts` for running a production Bun server.
712
+ - New subpath export `@deijose/nix-js-kit/adapters/bun`.
713
+
714
+ ### Changed
715
+
716
+ - CLI `adapter` command now accepts `vercel`, `netlify` and `bun`.
717
+ - README updated with Bun adapter instructions and roadmap v0.9.
718
+
719
+ ## 0.8.0
720
+
721
+ ### Added
722
+
723
+ - Netlify adapter: `nix-js-kit adapter netlify` generates a Netlify Functions v2 SSR function and `netlify.toml`.
724
+ - New subpath export `@deijose/nix-js-kit/adapters/netlify`.
725
+ - Shared adapter helpers in `src/adapters/shared.ts` used by both Vercel and Netlify adapters.
726
+
727
+ ### Changed
728
+
729
+ - CLI `adapter` command now accepts `vercel` and `netlify`.
730
+ - README updated with Netlify adapter instructions and roadmap v0.8.
731
+
732
+ ## 0.7.0
733
+
734
+ ### Added
735
+
736
+ - Vercel adapter: `nix-js-kit adapter vercel` generates a `.vercel/output` directory compatible with the Vercel Build Output API v3.
737
+ - New adapter interface in `src/adapters/index.ts`.
738
+ - New CLI command `nix-js-kit adapter <name>` (currently supports `vercel`).
739
+ - New subpath exports `@deijose/nix-js-kit/adapters` and `@deijose/nix-js-kit/adapters/vercel`.
740
+
741
+ ### Changed
742
+
743
+ - README updated with adapters section, CLI command list and roadmap v0.7/v0.8.
744
+
745
+ ## 0.6.1
746
+
747
+ ### Changed
748
+
749
+ - Renamed Vite plugin function from `nixKit` to `nixJsKit` and the options interface from `NixKitViteOptions` to `NixJsKitViteOptions` to keep the `js` word in the public API.
750
+ - Updated README, CHANGELOG and example import to use `nixJsKit`.
751
+
752
+ ## 0.6.0
753
+
754
+ ### Added
755
+
756
+ - Official Vite plugin: `import { nixJsKit } from "@deijose/nix-js-kit/vite"`.
757
+ - Vite plugin generates the islands entry automatically and renders pages via SSR on the Vite dev server.
758
+ - New subpath export `@deijose/nix-js-kit/vite` for plugin usage.
759
+ - Added `example/vite.config.ts` demonstrating the Vite plugin.
760
+
761
+ ### Changed
762
+
763
+ - README updated with Vite plugin section and roadmap v0.6/v0.7.
764
+
765
+ ## 0.5.0
766
+
767
+ ### Added
768
+
769
+ - SSR runtime: `nix-js-kit start` renders pages on demand and serves static assets from `dist/`.
770
+ - `matchRoute` URL matcher for dynamic and catch-all routes.
771
+ - `renderPage` shared renderer used by both SSG and SSR.
772
+ - `createSsrServer` exported from the public API for custom Node deployments.
773
+
774
+ ### Changed
775
+
776
+ - `src/build/build.ts` now uses the shared `renderPage` from `src/ssr/render.ts`.
777
+ - CLI help text and README updated to include the `start` command.
778
+
779
+ ## 0.4.2
780
+
781
+ ### Added
782
+
783
+ - Route groups `(marketing)` support: folders wrapped in parentheses are ignored in the URL path but can provide a shared `layout.ts`.
784
+ - Added `example/src/app/(marketing)/` with `pricing` and `features` pages demonstrating route groups.
785
+
786
+ ### Fixed
787
+
788
+ - Route scanner now reads `layout.ts` from inside the route group directory instead of the parent directory.
789
+
790
+ ## 0.4.1
791
+
792
+ ### Added
793
+
794
+ - `nix-js-kit preview` command to serve the static build in production mode.
795
+ - Clean URL support for static files (e.g. `/about` → `/about/index.html`).
796
+
797
+ ### Changed
798
+
799
+ - CLI help text and README updated to include the `preview` command.
800
+
801
+ ## 0.4.0
802
+
803
+ ### Added
804
+
805
+ - `generateStaticParams` export for dynamic routes (`[slug]`) and catch-all routes (`[...slug]`).
806
+ - Dynamic routes with `generateStaticParams` are now rendered to static HTML during SSG instead of being skipped.
807
+ - `GenerateStaticParams` type exported from the public API.
808
+ - Added `example/src/app/blog/[slug]` demonstrating a generated blog post route.
809
+
810
+ ### Changed
811
+
812
+ - Updated `tsconfig.json` with `paths` mapping so examples can import from `@deijose/nix-js-kit` during development and typechecking.
813
+
814
+ ## 0.3.1
815
+
816
+ ### Changed
817
+
818
+ - Renamed CLI binary from `nix-kit` to `nix-js-kit` to avoid confusion with the Nix package manager.
819
+ - Updated runtime warning prefix from `[nix-kit]` to `[nix-js-kit]`.
820
+
821
+ ## 0.3.0
822
+
823
+ ### Added
824
+
825
+ - `nix-js-kit` CLI binary with `build` and `dev` commands.
826
+ - Dev server (`nix-js-kit dev`) with rebuild-on-change for `src/app/` and `src/islands/`.
827
+ - `--client-config` option to rebuild the client hydration bundle on each source change.
828
+ - `run()` and `CliOptions` exported from `@deijose/nix-js-kit` for programmatic CLI usage.
829
+
830
+ ### Changed
831
+
832
+ - `build:lib` now produces a separate SSR build for `dist/lib/cli.js` so the CLI can import user `.ts` files at runtime.
833
+ - Added `tsx` as a runtime dependency so the CLI can load user pages and islands without extra setup.
834
+
835
+ ## 0.2.2
836
+
837
+ ### Added
838
+
839
+ - `scanIslands()` — recursively scans an islands directory; each `.ts` file becomes an island named by its relative path.
840
+ - `generateClientEntry()` / `buildEntrySource()` — generates the client hydration entry from scanned islands.
841
+ - `build()` now accepts `islandsDir`, `generatedEntry`, and `hydrateImport`; `BuildResult` reports `islands` and `generatedEntry`.
842
+ - Second example island (`Counter`) demonstrating multiple islands and the `visible` directive.
843
+
844
+ ## 0.2.1
845
+
846
+ ### Added
847
+
848
+ - `island()` helper — marks interactive components with `data-nix-island` markers during SSG.
849
+ - `hydrateIslands()` — client-side hydration registry with `load`, `idle`, and `visible` directives.
850
+ - `example/src/islands/` + `example/src/entry-client.ts` demonstrating a `LikeButton` island.
851
+ - `./island` subpath export so client bundles don't pull server-only code.
852
+
853
+ ## 0.2.0
854
+
855
+ ### Added
856
+
857
+ - `scanRoutes` — file-based route scanner that maps `src/app/page.ts` to URL paths, including dynamic segments (`[slug]`, `[...slug]`).
858
+ - `build` — SSG orchestrator that scans `src/app/`, runs loaders, composes layout chains, renders pages, and writes static HTML.
859
+ - Example app with two pages (`/`, `/about`) sharing a root layout.
860
+
861
+ ## 0.1.0
862
+
863
+ ### Added
864
+
865
+ - Initial release of `@deijose/nix-js-kit`.
866
+ - `renderToString` for Nix.js templates using `happy-dom` as a build-time DOM (client bundle remains dependency-free).
867
+ - `documentShell` helper to wrap rendered HTML with a full document shell and serialize loader data via `<script id="nix-js-data">`.
868
+ - Public types: `PageProps`, `LayoutProps`, `PageDataLoad`, `LoadContext`, `RouteParams`, `ShellOptions`.
869
+ - Proof-of-concept example under `example/` that generates `dist/index.html` from a `page.ts` + `page.data.ts` pair.
870
+ - Vite library build configuration and TypeScript declaration generation.
871
+
872
+ ### Notes
873
+
874
+ - `linkedom` was evaluated as a lighter DOM alternative but rejected because it does not expose `NodeFilter` in a way compatible with the Nix.js core (`template2.js` reads `NodeFilter.SHOW_ELEMENT` from `globalThis`).