fuzor 0.3.0 → 0.5.0

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 (929) hide show
  1. package/README.md +36 -88
  2. package/dist/boundaries.d.ts +5 -0
  3. package/dist/boundaries.d.ts.map +1 -0
  4. package/dist/boundaries.js +5 -0
  5. package/dist/boundaries.js.map +1 -0
  6. package/dist/browser.d.ts +4 -0
  7. package/dist/browser.d.ts.map +1 -0
  8. package/dist/browser.js +4 -0
  9. package/dist/browser.js.map +1 -0
  10. package/dist/build-output.d.ts +18 -0
  11. package/dist/build-output.d.ts.map +1 -0
  12. package/dist/build-output.js +91 -0
  13. package/dist/build-output.js.map +1 -0
  14. package/dist/cli.js +390 -36
  15. package/dist/cli.js.map +1 -1
  16. package/dist/compiler/api-routes.d.ts +14 -0
  17. package/dist/compiler/api-routes.d.ts.map +1 -0
  18. package/dist/compiler/api-routes.js +66 -0
  19. package/dist/compiler/api-routes.js.map +1 -0
  20. package/dist/compiler/base-links.d.ts +7 -0
  21. package/dist/compiler/base-links.d.ts.map +1 -0
  22. package/dist/compiler/base-links.js +40 -0
  23. package/dist/compiler/base-links.js.map +1 -0
  24. package/dist/compiler/data-document.d.ts +9 -0
  25. package/dist/compiler/data-document.d.ts.map +1 -0
  26. package/dist/compiler/data-document.js +21 -0
  27. package/dist/compiler/data-document.js.map +1 -0
  28. package/dist/compiler/docs.d.ts +6 -0
  29. package/dist/compiler/docs.d.ts.map +1 -0
  30. package/dist/compiler/docs.js +1131 -0
  31. package/dist/compiler/docs.js.map +1 -0
  32. package/dist/compiler/highlight.d.ts +13 -0
  33. package/dist/compiler/highlight.d.ts.map +1 -0
  34. package/dist/compiler/highlight.js +44 -0
  35. package/dist/compiler/highlight.js.map +1 -0
  36. package/dist/compiler/index.d.ts +132 -4
  37. package/dist/compiler/index.d.ts.map +1 -1
  38. package/dist/compiler/index.js +845 -48
  39. package/dist/compiler/index.js.map +1 -1
  40. package/dist/compiler/inline-assets.d.ts +6 -0
  41. package/dist/compiler/inline-assets.d.ts.map +1 -0
  42. package/dist/compiler/inline-assets.js +61 -0
  43. package/dist/compiler/inline-assets.js.map +1 -0
  44. package/dist/compiler/inline-modules.d.ts +7 -0
  45. package/dist/compiler/inline-modules.d.ts.map +1 -0
  46. package/dist/compiler/inline-modules.js +77 -0
  47. package/dist/compiler/inline-modules.js.map +1 -0
  48. package/dist/compiler/island-modules.d.ts +8 -0
  49. package/dist/compiler/island-modules.d.ts.map +1 -0
  50. package/dist/compiler/island-modules.js +42 -0
  51. package/dist/compiler/island-modules.js.map +1 -0
  52. package/dist/compiler/islands.d.ts +24 -3
  53. package/dist/compiler/islands.d.ts.map +1 -1
  54. package/dist/compiler/islands.js +50 -12
  55. package/dist/compiler/islands.js.map +1 -1
  56. package/dist/compiler/links.d.ts +37 -0
  57. package/dist/compiler/links.d.ts.map +1 -0
  58. package/dist/compiler/links.js +112 -0
  59. package/dist/compiler/links.js.map +1 -0
  60. package/dist/compiler/markdown.d.ts +17 -0
  61. package/dist/compiler/markdown.d.ts.map +1 -0
  62. package/dist/compiler/markdown.js +92 -0
  63. package/dist/compiler/markdown.js.map +1 -0
  64. package/dist/compiler/metadata.d.ts +37 -0
  65. package/dist/compiler/metadata.d.ts.map +1 -0
  66. package/dist/compiler/metadata.js +81 -0
  67. package/dist/compiler/metadata.js.map +1 -0
  68. package/dist/compiler/native-scripts.d.ts +13 -0
  69. package/dist/compiler/native-scripts.d.ts.map +1 -0
  70. package/dist/compiler/native-scripts.js +137 -0
  71. package/dist/compiler/native-scripts.js.map +1 -0
  72. package/dist/compiler/page-scripts.d.ts +36 -0
  73. package/dist/compiler/page-scripts.d.ts.map +1 -0
  74. package/dist/compiler/page-scripts.js +158 -0
  75. package/dist/compiler/page-scripts.js.map +1 -0
  76. package/dist/compiler/route-policy.d.ts +17 -0
  77. package/dist/compiler/route-policy.d.ts.map +1 -0
  78. package/dist/compiler/route-policy.js +68 -0
  79. package/dist/compiler/route-policy.js.map +1 -0
  80. package/dist/compiler/search.d.ts +13 -0
  81. package/dist/compiler/search.d.ts.map +1 -0
  82. package/dist/compiler/search.js +24 -0
  83. package/dist/compiler/search.js.map +1 -0
  84. package/dist/compiler/server-modules.d.ts +3 -0
  85. package/dist/compiler/server-modules.d.ts.map +1 -0
  86. package/dist/compiler/server-modules.js +31 -0
  87. package/dist/compiler/server-modules.js.map +1 -0
  88. package/dist/compiler/static-analysis.d.ts +20 -0
  89. package/dist/compiler/static-analysis.d.ts.map +1 -0
  90. package/dist/compiler/static-analysis.js +130 -0
  91. package/dist/compiler/static-analysis.js.map +1 -0
  92. package/dist/create-delegate.d.ts +17 -0
  93. package/dist/create-delegate.d.ts.map +1 -0
  94. package/dist/create-delegate.js +48 -0
  95. package/dist/create-delegate.js.map +1 -0
  96. package/dist/electron.d.ts +5 -0
  97. package/dist/electron.d.ts.map +1 -0
  98. package/dist/electron.js +32 -0
  99. package/dist/electron.js.map +1 -0
  100. package/dist/html-escape.d.ts +16 -0
  101. package/dist/html-escape.d.ts.map +1 -0
  102. package/dist/html-escape.js +26 -0
  103. package/dist/html-escape.js.map +1 -0
  104. package/dist/index.d.ts +6 -4
  105. package/dist/index.d.ts.map +1 -1
  106. package/dist/index.js +4 -3
  107. package/dist/index.js.map +1 -1
  108. package/dist/islands/hydration.d.ts +7 -0
  109. package/dist/islands/hydration.d.ts.map +1 -0
  110. package/dist/islands/hydration.js +12 -0
  111. package/dist/islands/hydration.js.map +1 -0
  112. package/dist/islands/react.d.ts +9 -2
  113. package/dist/islands/react.d.ts.map +1 -1
  114. package/dist/islands/react.js +73 -14
  115. package/dist/islands/react.js.map +1 -1
  116. package/dist/islands/solid.d.ts.map +1 -1
  117. package/dist/islands/solid.js +10 -1
  118. package/dist/islands/solid.js.map +1 -1
  119. package/dist/islands/vue.d.ts.map +1 -1
  120. package/dist/islands/vue.js +15 -3
  121. package/dist/islands/vue.js.map +1 -1
  122. package/dist/module-specifiers.d.ts +5 -0
  123. package/dist/module-specifiers.d.ts.map +1 -0
  124. package/dist/module-specifiers.js +80 -0
  125. package/dist/module-specifiers.js.map +1 -0
  126. package/dist/route-path.d.ts +33 -0
  127. package/dist/route-path.d.ts.map +1 -0
  128. package/dist/route-path.js +81 -0
  129. package/dist/route-path.js.map +1 -0
  130. package/dist/route-patterns.d.ts +8 -0
  131. package/dist/route-patterns.d.ts.map +1 -0
  132. package/dist/route-patterns.js +84 -0
  133. package/dist/route-patterns.js.map +1 -0
  134. package/dist/runtime/activation.d.ts +29 -0
  135. package/dist/runtime/activation.d.ts.map +1 -0
  136. package/dist/runtime/activation.js +236 -0
  137. package/dist/runtime/activation.js.map +1 -0
  138. package/dist/runtime/browser-navigation.d.ts +20 -0
  139. package/dist/runtime/browser-navigation.d.ts.map +1 -0
  140. package/dist/runtime/browser-navigation.js +138 -0
  141. package/dist/runtime/browser-navigation.js.map +1 -0
  142. package/dist/runtime/browser-support.d.ts +20 -0
  143. package/dist/runtime/browser-support.d.ts.map +1 -0
  144. package/dist/runtime/browser-support.js +39 -0
  145. package/dist/runtime/browser-support.js.map +1 -0
  146. package/dist/runtime/capacitor.d.ts +43 -0
  147. package/dist/runtime/capacitor.d.ts.map +1 -0
  148. package/dist/runtime/capacitor.js +84 -0
  149. package/dist/runtime/capacitor.js.map +1 -0
  150. package/dist/runtime/client-routes.d.ts +4 -0
  151. package/dist/runtime/client-routes.d.ts.map +1 -0
  152. package/dist/runtime/client-routes.js +3 -0
  153. package/dist/runtime/client-routes.js.map +1 -0
  154. package/dist/runtime/coordinated-navigation.d.ts +7 -0
  155. package/dist/runtime/coordinated-navigation.d.ts.map +1 -0
  156. package/dist/runtime/coordinated-navigation.js +50 -0
  157. package/dist/runtime/coordinated-navigation.js.map +1 -0
  158. package/dist/runtime/coordinator.d.ts +32 -0
  159. package/dist/runtime/coordinator.d.ts.map +1 -0
  160. package/dist/runtime/coordinator.js +115 -0
  161. package/dist/runtime/coordinator.js.map +1 -0
  162. package/dist/runtime/data.d.ts +25 -0
  163. package/dist/runtime/data.d.ts.map +1 -0
  164. package/dist/runtime/data.js +115 -0
  165. package/dist/runtime/data.js.map +1 -0
  166. package/dist/runtime/docs-search.d.ts +13 -0
  167. package/dist/runtime/docs-search.d.ts.map +1 -0
  168. package/dist/runtime/docs-search.js +205 -0
  169. package/dist/runtime/docs-search.js.map +1 -0
  170. package/dist/runtime/docs-ui.d.ts +7 -0
  171. package/dist/runtime/docs-ui.d.ts.map +1 -0
  172. package/dist/runtime/docs-ui.js +85 -0
  173. package/dist/runtime/docs-ui.js.map +1 -0
  174. package/dist/runtime/document-navigation.d.ts +9 -0
  175. package/dist/runtime/document-navigation.d.ts.map +1 -0
  176. package/dist/runtime/document-navigation.js +27 -0
  177. package/dist/runtime/document-navigation.js.map +1 -0
  178. package/dist/runtime/dom-renderer.d.ts +36 -0
  179. package/dist/runtime/dom-renderer.d.ts.map +1 -0
  180. package/dist/runtime/dom-renderer.js +173 -0
  181. package/dist/runtime/dom-renderer.js.map +1 -0
  182. package/dist/runtime/hash-navigation.d.ts +12 -0
  183. package/dist/runtime/hash-navigation.d.ts.map +1 -0
  184. package/dist/runtime/hash-navigation.js +26 -0
  185. package/dist/runtime/hash-navigation.js.map +1 -0
  186. package/dist/runtime/history-navigation.d.ts +17 -0
  187. package/dist/runtime/history-navigation.d.ts.map +1 -0
  188. package/dist/runtime/history-navigation.js +172 -0
  189. package/dist/runtime/history-navigation.js.map +1 -0
  190. package/dist/runtime/href.d.ts +16 -0
  191. package/dist/runtime/href.d.ts.map +1 -0
  192. package/dist/runtime/href.js +38 -0
  193. package/dist/runtime/href.js.map +1 -0
  194. package/dist/runtime/index.d.ts +73 -26
  195. package/dist/runtime/index.d.ts.map +1 -1
  196. package/dist/runtime/index.js +33 -118
  197. package/dist/runtime/index.js.map +1 -1
  198. package/dist/runtime/initial-route.d.ts +8 -0
  199. package/dist/runtime/initial-route.d.ts.map +1 -0
  200. package/dist/runtime/initial-route.js +72 -0
  201. package/dist/runtime/initial-route.js.map +1 -0
  202. package/dist/runtime/islands.d.ts +19 -5
  203. package/dist/runtime/islands.d.ts.map +1 -1
  204. package/dist/runtime/islands.js +15 -41
  205. package/dist/runtime/islands.js.map +1 -1
  206. package/dist/runtime/loading.d.ts +12 -0
  207. package/dist/runtime/loading.d.ts.map +1 -0
  208. package/dist/runtime/loading.js +43 -0
  209. package/dist/runtime/loading.js.map +1 -0
  210. package/dist/runtime/memory-navigation.d.ts +16 -0
  211. package/dist/runtime/memory-navigation.d.ts.map +1 -0
  212. package/dist/runtime/memory-navigation.js +98 -0
  213. package/dist/runtime/memory-navigation.js.map +1 -0
  214. package/dist/runtime/native.d.ts +108 -0
  215. package/dist/runtime/native.d.ts.map +1 -0
  216. package/dist/runtime/native.js +378 -0
  217. package/dist/runtime/native.js.map +1 -0
  218. package/dist/runtime/navigation-atom.d.ts +21 -0
  219. package/dist/runtime/navigation-atom.d.ts.map +1 -0
  220. package/dist/runtime/navigation-atom.js +76 -0
  221. package/dist/runtime/navigation-atom.js.map +1 -0
  222. package/dist/runtime/navigation.d.ts +61 -0
  223. package/dist/runtime/navigation.d.ts.map +1 -0
  224. package/dist/runtime/navigation.js +11 -0
  225. package/dist/runtime/navigation.js.map +1 -0
  226. package/dist/runtime/page-scripts.d.ts +54 -0
  227. package/dist/runtime/page-scripts.d.ts.map +1 -0
  228. package/dist/runtime/page-scripts.js +207 -0
  229. package/dist/runtime/page-scripts.js.map +1 -0
  230. package/dist/runtime/route-matches.d.ts +17 -0
  231. package/dist/runtime/route-matches.d.ts.map +1 -0
  232. package/dist/runtime/route-matches.js +50 -0
  233. package/dist/runtime/route-matches.js.map +1 -0
  234. package/dist/runtime/router-embedded.d.ts +28 -0
  235. package/dist/runtime/router-embedded.d.ts.map +1 -0
  236. package/dist/runtime/router-embedded.js +12 -0
  237. package/dist/runtime/router-embedded.js.map +1 -0
  238. package/dist/runtime/router-navigation-api.d.ts +28 -0
  239. package/dist/runtime/router-navigation-api.d.ts.map +1 -0
  240. package/dist/runtime/router-navigation-api.js +13 -0
  241. package/dist/runtime/router-navigation-api.js.map +1 -0
  242. package/dist/runtime/router.d.ts +137 -0
  243. package/dist/runtime/router.d.ts.map +1 -0
  244. package/dist/runtime/router.js +678 -0
  245. package/dist/runtime/router.js.map +1 -0
  246. package/dist/runtime/stale-deployment.d.ts +7 -0
  247. package/dist/runtime/stale-deployment.d.ts.map +1 -0
  248. package/dist/runtime/stale-deployment.js +30 -0
  249. package/dist/runtime/stale-deployment.js.map +1 -0
  250. package/dist/runtime/user-input.d.ts +25 -0
  251. package/dist/runtime/user-input.d.ts.map +1 -0
  252. package/dist/runtime/user-input.js +81 -0
  253. package/dist/runtime/user-input.js.map +1 -0
  254. package/dist/runtimes.d.ts +43 -0
  255. package/dist/runtimes.d.ts.map +1 -0
  256. package/dist/runtimes.js +152 -0
  257. package/dist/runtimes.js.map +1 -0
  258. package/dist/server/node.d.ts +47 -2
  259. package/dist/server/node.d.ts.map +1 -1
  260. package/dist/server/node.js +185 -23
  261. package/dist/server/node.js.map +1 -1
  262. package/dist/server/static.d.ts +11 -0
  263. package/dist/server/static.d.ts.map +1 -0
  264. package/dist/server/static.js +61 -0
  265. package/dist/server/static.js.map +1 -0
  266. package/dist/server-api.d.ts +73 -0
  267. package/dist/server-api.d.ts.map +1 -0
  268. package/dist/server-api.js +171 -0
  269. package/dist/server-api.js.map +1 -0
  270. package/dist/server-components/browser.d.ts +75 -0
  271. package/dist/server-components/browser.d.ts.map +1 -0
  272. package/dist/server-components/browser.js +558 -0
  273. package/dist/server-components/browser.js.map +1 -0
  274. package/dist/server-components/closures.d.ts +21 -0
  275. package/dist/server-components/closures.d.ts.map +1 -0
  276. package/dist/server-components/closures.js +192 -0
  277. package/dist/server-components/closures.js.map +1 -0
  278. package/dist/server-components/compiler.d.ts +6 -0
  279. package/dist/server-components/compiler.d.ts.map +1 -0
  280. package/dist/server-components/compiler.js +118 -0
  281. package/dist/server-components/compiler.js.map +1 -0
  282. package/dist/server-components/environment.d.ts +3 -0
  283. package/dist/server-components/environment.d.ts.map +1 -0
  284. package/dist/server-components/environment.js +11 -0
  285. package/dist/server-components/environment.js.map +1 -0
  286. package/dist/server-components/navigation.d.ts +10 -0
  287. package/dist/server-components/navigation.d.ts.map +1 -0
  288. package/dist/server-components/navigation.js +105 -0
  289. package/dist/server-components/navigation.js.map +1 -0
  290. package/dist/server-components/protocol.d.ts +77 -0
  291. package/dist/server-components/protocol.d.ts.map +1 -0
  292. package/dist/server-components/protocol.js +110 -0
  293. package/dist/server-components/protocol.js.map +1 -0
  294. package/dist/server-components/references.d.ts +22 -0
  295. package/dist/server-components/references.d.ts.map +1 -0
  296. package/dist/server-components/references.js +94 -0
  297. package/dist/server-components/references.js.map +1 -0
  298. package/dist/server-components/server.d.ts +78 -0
  299. package/dist/server-components/server.d.ts.map +1 -0
  300. package/dist/server-components/server.js +278 -0
  301. package/dist/server-components/server.js.map +1 -0
  302. package/dist/server-components/stream.d.ts +15 -0
  303. package/dist/server-components/stream.d.ts.map +1 -0
  304. package/dist/server-components/stream.js +72 -0
  305. package/dist/server-components/stream.js.map +1 -0
  306. package/dist/server-cookies.d.ts +41 -0
  307. package/dist/server-cookies.d.ts.map +1 -0
  308. package/dist/server-cookies.js +120 -0
  309. package/dist/server-cookies.js.map +1 -0
  310. package/dist/server-data.d.ts +51 -0
  311. package/dist/server-data.d.ts.map +1 -0
  312. package/dist/server-data.js +37 -0
  313. package/dist/server-data.js.map +1 -0
  314. package/dist/server.d.ts +57 -4
  315. package/dist/server.d.ts.map +1 -1
  316. package/dist/server.js +244 -13
  317. package/dist/server.js.map +1 -1
  318. package/dist/ui/behaviors/accordion.d.ts +14 -0
  319. package/dist/ui/behaviors/accordion.d.ts.map +1 -0
  320. package/dist/ui/behaviors/accordion.js +149 -0
  321. package/dist/ui/behaviors/accordion.js.map +1 -0
  322. package/dist/ui/behaviors/catalogue.d.ts +63 -0
  323. package/dist/ui/behaviors/catalogue.d.ts.map +1 -0
  324. package/dist/ui/behaviors/catalogue.js +284 -0
  325. package/dist/ui/behaviors/catalogue.js.map +1 -0
  326. package/dist/ui/behaviors/collapsible.d.ts +26 -0
  327. package/dist/ui/behaviors/collapsible.d.ts.map +1 -0
  328. package/dist/ui/behaviors/collapsible.js +145 -0
  329. package/dist/ui/behaviors/collapsible.js.map +1 -0
  330. package/dist/ui/behaviors/dialog.d.ts +16 -0
  331. package/dist/ui/behaviors/dialog.d.ts.map +1 -0
  332. package/dist/ui/behaviors/dialog.js +225 -0
  333. package/dist/ui/behaviors/dialog.js.map +1 -0
  334. package/dist/ui/behaviors/lifecycle.d.ts +15 -0
  335. package/dist/ui/behaviors/lifecycle.d.ts.map +1 -0
  336. package/dist/ui/behaviors/lifecycle.js +51 -0
  337. package/dist/ui/behaviors/lifecycle.js.map +1 -0
  338. package/dist/ui/behaviors/menu.d.ts +15 -0
  339. package/dist/ui/behaviors/menu.d.ts.map +1 -0
  340. package/dist/ui/behaviors/menu.js +162 -0
  341. package/dist/ui/behaviors/menu.js.map +1 -0
  342. package/dist/ui/behaviors/ownership.d.ts +7 -0
  343. package/dist/ui/behaviors/ownership.d.ts.map +1 -0
  344. package/dist/ui/behaviors/ownership.js +16 -0
  345. package/dist/ui/behaviors/ownership.js.map +1 -0
  346. package/dist/ui/behaviors/popover.d.ts +16 -0
  347. package/dist/ui/behaviors/popover.d.ts.map +1 -0
  348. package/dist/ui/behaviors/popover.js +90 -0
  349. package/dist/ui/behaviors/popover.js.map +1 -0
  350. package/dist/ui/behaviors/select.d.ts +37 -0
  351. package/dist/ui/behaviors/select.d.ts.map +1 -0
  352. package/dist/ui/behaviors/select.js +261 -0
  353. package/dist/ui/behaviors/select.js.map +1 -0
  354. package/dist/ui/behaviors/switch.d.ts +43 -0
  355. package/dist/ui/behaviors/switch.d.ts.map +1 -0
  356. package/dist/ui/behaviors/switch.js +269 -0
  357. package/dist/ui/behaviors/switch.js.map +1 -0
  358. package/dist/ui/behaviors/tabs.d.ts +4 -0
  359. package/dist/ui/behaviors/tabs.d.ts.map +1 -0
  360. package/dist/ui/behaviors/tabs.js +121 -0
  361. package/dist/ui/behaviors/tabs.js.map +1 -0
  362. package/dist/ui/behaviors/toolbar.d.ts +4 -0
  363. package/dist/ui/behaviors/toolbar.d.ts.map +1 -0
  364. package/dist/ui/behaviors/toolbar.js +81 -0
  365. package/dist/ui/behaviors/toolbar.js.map +1 -0
  366. package/dist/ui/behaviors/tooltip.d.ts +16 -0
  367. package/dist/ui/behaviors/tooltip.d.ts.map +1 -0
  368. package/dist/ui/behaviors/tooltip.js +91 -0
  369. package/dist/ui/behaviors/tooltip.js.map +1 -0
  370. package/dist/ui/behaviors/types.d.ts +51 -0
  371. package/dist/ui/behaviors/types.d.ts.map +1 -0
  372. package/dist/ui/behaviors/types.js +2 -0
  373. package/dist/ui/behaviors/types.js.map +1 -0
  374. package/dist/ui/catalogue-loaders.d.ts +4 -0
  375. package/dist/ui/catalogue-loaders.d.ts.map +1 -0
  376. package/dist/ui/catalogue-loaders.js +45 -0
  377. package/dist/ui/catalogue-loaders.js.map +1 -0
  378. package/dist/ui/catalogue.d.ts +465 -0
  379. package/dist/ui/catalogue.d.ts.map +1 -0
  380. package/dist/ui/catalogue.js +1570 -0
  381. package/dist/ui/catalogue.js.map +1 -0
  382. package/dist/ui/checkpoints.d.ts +20 -0
  383. package/dist/ui/checkpoints.d.ts.map +1 -0
  384. package/dist/ui/checkpoints.js +118 -0
  385. package/dist/ui/checkpoints.js.map +1 -0
  386. package/dist/ui/components/accordion/accordion.d.ts +22 -0
  387. package/dist/ui/components/accordion/accordion.d.ts.map +1 -0
  388. package/dist/ui/components/accordion/accordion.js +47 -0
  389. package/dist/ui/components/accordion/accordion.js.map +1 -0
  390. package/dist/ui/components/accordion/index.d.ts +2 -0
  391. package/dist/ui/components/accordion/index.d.ts.map +1 -0
  392. package/dist/ui/components/accordion/index.js +2 -0
  393. package/dist/ui/components/accordion/index.js.map +1 -0
  394. package/dist/ui/components/angle-slider/index.d.ts +5 -0
  395. package/dist/ui/components/angle-slider/index.d.ts.map +1 -0
  396. package/dist/ui/components/angle-slider/index.js +7 -0
  397. package/dist/ui/components/angle-slider/index.js.map +1 -0
  398. package/dist/ui/components/async-list/index.d.ts +5 -0
  399. package/dist/ui/components/async-list/index.d.ts.map +1 -0
  400. package/dist/ui/components/async-list/index.js +7 -0
  401. package/dist/ui/components/async-list/index.js.map +1 -0
  402. package/dist/ui/components/avatar/index.d.ts +5 -0
  403. package/dist/ui/components/avatar/index.d.ts.map +1 -0
  404. package/dist/ui/components/avatar/index.js +7 -0
  405. package/dist/ui/components/avatar/index.js.map +1 -0
  406. package/dist/ui/components/badge/badge.d.ts +6 -0
  407. package/dist/ui/components/badge/badge.d.ts.map +1 -0
  408. package/dist/ui/components/badge/badge.js +11 -0
  409. package/dist/ui/components/badge/badge.js.map +1 -0
  410. package/dist/ui/components/badge/index.d.ts +2 -0
  411. package/dist/ui/components/badge/index.d.ts.map +1 -0
  412. package/dist/ui/components/badge/index.js +2 -0
  413. package/dist/ui/components/badge/index.js.map +1 -0
  414. package/dist/ui/components/button/button.d.ts +26 -0
  415. package/dist/ui/components/button/button.d.ts.map +1 -0
  416. package/dist/ui/components/button/button.js +116 -0
  417. package/dist/ui/components/button/button.js.map +1 -0
  418. package/dist/ui/components/button/index.d.ts +2 -0
  419. package/dist/ui/components/button/index.d.ts.map +1 -0
  420. package/dist/ui/components/button/index.js +2 -0
  421. package/dist/ui/components/button/index.js.map +1 -0
  422. package/dist/ui/components/card/card.d.ts +21 -0
  423. package/dist/ui/components/card/card.d.ts.map +1 -0
  424. package/dist/ui/components/card/card.js +41 -0
  425. package/dist/ui/components/card/card.js.map +1 -0
  426. package/dist/ui/components/card/index.d.ts +2 -0
  427. package/dist/ui/components/card/index.d.ts.map +1 -0
  428. package/dist/ui/components/card/index.js +2 -0
  429. package/dist/ui/components/card/index.js.map +1 -0
  430. package/dist/ui/components/carousel/index.d.ts +5 -0
  431. package/dist/ui/components/carousel/index.d.ts.map +1 -0
  432. package/dist/ui/components/carousel/index.js +7 -0
  433. package/dist/ui/components/carousel/index.js.map +1 -0
  434. package/dist/ui/components/cascade-select/index.d.ts +7 -0
  435. package/dist/ui/components/cascade-select/index.d.ts.map +1 -0
  436. package/dist/ui/components/cascade-select/index.js +8 -0
  437. package/dist/ui/components/cascade-select/index.js.map +1 -0
  438. package/dist/ui/components/checkbox/index.d.ts +5 -0
  439. package/dist/ui/components/checkbox/index.d.ts.map +1 -0
  440. package/dist/ui/components/checkbox/index.js +7 -0
  441. package/dist/ui/components/checkbox/index.js.map +1 -0
  442. package/dist/ui/components/clipboard/index.d.ts +5 -0
  443. package/dist/ui/components/clipboard/index.d.ts.map +1 -0
  444. package/dist/ui/components/clipboard/index.js +7 -0
  445. package/dist/ui/components/clipboard/index.js.map +1 -0
  446. package/dist/ui/components/collapsible/collapsible.d.ts +21 -0
  447. package/dist/ui/components/collapsible/collapsible.d.ts.map +1 -0
  448. package/dist/ui/components/collapsible/collapsible.js +39 -0
  449. package/dist/ui/components/collapsible/collapsible.js.map +1 -0
  450. package/dist/ui/components/collapsible/index.d.ts +2 -0
  451. package/dist/ui/components/collapsible/index.d.ts.map +1 -0
  452. package/dist/ui/components/collapsible/index.js +2 -0
  453. package/dist/ui/components/collapsible/index.js.map +1 -0
  454. package/dist/ui/components/color-picker/index.d.ts +7 -0
  455. package/dist/ui/components/color-picker/index.d.ts.map +1 -0
  456. package/dist/ui/components/color-picker/index.js +8 -0
  457. package/dist/ui/components/color-picker/index.js.map +1 -0
  458. package/dist/ui/components/combobox/index.d.ts +7 -0
  459. package/dist/ui/components/combobox/index.d.ts.map +1 -0
  460. package/dist/ui/components/combobox/index.js +8 -0
  461. package/dist/ui/components/combobox/index.js.map +1 -0
  462. package/dist/ui/components/date-input/index.d.ts +7 -0
  463. package/dist/ui/components/date-input/index.d.ts.map +1 -0
  464. package/dist/ui/components/date-input/index.js +8 -0
  465. package/dist/ui/components/date-input/index.js.map +1 -0
  466. package/dist/ui/components/date-picker/index.d.ts +7 -0
  467. package/dist/ui/components/date-picker/index.d.ts.map +1 -0
  468. package/dist/ui/components/date-picker/index.js +8 -0
  469. package/dist/ui/components/date-picker/index.js.map +1 -0
  470. package/dist/ui/components/dialog/dialog.d.ts +44 -0
  471. package/dist/ui/components/dialog/dialog.d.ts.map +1 -0
  472. package/dist/ui/components/dialog/dialog.js +105 -0
  473. package/dist/ui/components/dialog/dialog.js.map +1 -0
  474. package/dist/ui/components/dialog/index.d.ts +2 -0
  475. package/dist/ui/components/dialog/index.d.ts.map +1 -0
  476. package/dist/ui/components/dialog/index.js +2 -0
  477. package/dist/ui/components/dialog/index.js.map +1 -0
  478. package/dist/ui/components/drawer/index.d.ts +5 -0
  479. package/dist/ui/components/drawer/index.d.ts.map +1 -0
  480. package/dist/ui/components/drawer/index.js +7 -0
  481. package/dist/ui/components/drawer/index.js.map +1 -0
  482. package/dist/ui/components/editable/index.d.ts +5 -0
  483. package/dist/ui/components/editable/index.d.ts.map +1 -0
  484. package/dist/ui/components/editable/index.js +7 -0
  485. package/dist/ui/components/editable/index.js.map +1 -0
  486. package/dist/ui/components/file-upload/index.d.ts +5 -0
  487. package/dist/ui/components/file-upload/index.d.ts.map +1 -0
  488. package/dist/ui/components/file-upload/index.js +7 -0
  489. package/dist/ui/components/file-upload/index.js.map +1 -0
  490. package/dist/ui/components/floating-panel/index.d.ts +5 -0
  491. package/dist/ui/components/floating-panel/index.d.ts.map +1 -0
  492. package/dist/ui/components/floating-panel/index.js +7 -0
  493. package/dist/ui/components/floating-panel/index.js.map +1 -0
  494. package/dist/ui/components/hover-card/index.d.ts +5 -0
  495. package/dist/ui/components/hover-card/index.d.ts.map +1 -0
  496. package/dist/ui/components/hover-card/index.js +7 -0
  497. package/dist/ui/components/hover-card/index.js.map +1 -0
  498. package/dist/ui/components/image-cropper/index.d.ts +5 -0
  499. package/dist/ui/components/image-cropper/index.d.ts.map +1 -0
  500. package/dist/ui/components/image-cropper/index.js +7 -0
  501. package/dist/ui/components/image-cropper/index.js.map +1 -0
  502. package/dist/ui/components/index.d.ts +61 -0
  503. package/dist/ui/components/index.d.ts.map +1 -0
  504. package/dist/ui/components/index.js +186 -0
  505. package/dist/ui/components/index.js.map +1 -0
  506. package/dist/ui/components/layout/box.d.ts +11 -0
  507. package/dist/ui/components/layout/box.d.ts.map +1 -0
  508. package/dist/ui/components/layout/box.js +44 -0
  509. package/dist/ui/components/layout/box.js.map +1 -0
  510. package/dist/ui/components/layout/container.d.ts +9 -0
  511. package/dist/ui/components/layout/container.d.ts.map +1 -0
  512. package/dist/ui/components/layout/container.js +38 -0
  513. package/dist/ui/components/layout/container.js.map +1 -0
  514. package/dist/ui/components/layout/flex.d.ts +10 -0
  515. package/dist/ui/components/layout/flex.d.ts.map +1 -0
  516. package/dist/ui/components/layout/flex.js +53 -0
  517. package/dist/ui/components/layout/flex.js.map +1 -0
  518. package/dist/ui/components/layout/grid.d.ts +10 -0
  519. package/dist/ui/components/layout/grid.d.ts.map +1 -0
  520. package/dist/ui/components/layout/grid.js +47 -0
  521. package/dist/ui/components/layout/grid.js.map +1 -0
  522. package/dist/ui/components/layout/index.d.ts +6 -0
  523. package/dist/ui/components/layout/index.d.ts.map +1 -0
  524. package/dist/ui/components/layout/index.js +6 -0
  525. package/dist/ui/components/layout/index.js.map +1 -0
  526. package/dist/ui/components/layout/stack.d.ts +9 -0
  527. package/dist/ui/components/layout/stack.d.ts.map +1 -0
  528. package/dist/ui/components/layout/stack.js +37 -0
  529. package/dist/ui/components/layout/stack.js.map +1 -0
  530. package/dist/ui/components/listbox/index.d.ts +8 -0
  531. package/dist/ui/components/listbox/index.d.ts.map +1 -0
  532. package/dist/ui/components/listbox/index.js +9 -0
  533. package/dist/ui/components/listbox/index.js.map +1 -0
  534. package/dist/ui/components/marquee/index.d.ts +5 -0
  535. package/dist/ui/components/marquee/index.d.ts.map +1 -0
  536. package/dist/ui/components/marquee/index.js +7 -0
  537. package/dist/ui/components/marquee/index.js.map +1 -0
  538. package/dist/ui/components/menu/index.d.ts +2 -0
  539. package/dist/ui/components/menu/index.d.ts.map +1 -0
  540. package/dist/ui/components/menu/index.js +2 -0
  541. package/dist/ui/components/menu/index.js.map +1 -0
  542. package/dist/ui/components/menu/menu.d.ts +23 -0
  543. package/dist/ui/components/menu/menu.d.ts.map +1 -0
  544. package/dist/ui/components/menu/menu.js +45 -0
  545. package/dist/ui/components/menu/menu.js.map +1 -0
  546. package/dist/ui/components/navigation/breadcrumbs.d.ts +19 -0
  547. package/dist/ui/components/navigation/breadcrumbs.d.ts.map +1 -0
  548. package/dist/ui/components/navigation/breadcrumbs.js +90 -0
  549. package/dist/ui/components/navigation/breadcrumbs.js.map +1 -0
  550. package/dist/ui/components/navigation/index.d.ts +6 -0
  551. package/dist/ui/components/navigation/index.d.ts.map +1 -0
  552. package/dist/ui/components/navigation/index.js +6 -0
  553. package/dist/ui/components/navigation/index.js.map +1 -0
  554. package/dist/ui/components/navigation/prose.d.ts +6 -0
  555. package/dist/ui/components/navigation/prose.d.ts.map +1 -0
  556. package/dist/ui/components/navigation/prose.js +11 -0
  557. package/dist/ui/components/navigation/prose.js.map +1 -0
  558. package/dist/ui/components/navigation/sidebar.d.ts +10 -0
  559. package/dist/ui/components/navigation/sidebar.d.ts.map +1 -0
  560. package/dist/ui/components/navigation/sidebar.js +35 -0
  561. package/dist/ui/components/navigation/sidebar.js.map +1 -0
  562. package/dist/ui/components/navigation/toc.d.ts +11 -0
  563. package/dist/ui/components/navigation/toc.d.ts.map +1 -0
  564. package/dist/ui/components/navigation/toc.js +82 -0
  565. package/dist/ui/components/navigation/toc.js.map +1 -0
  566. package/dist/ui/components/navigation-menu/index.d.ts +5 -0
  567. package/dist/ui/components/navigation-menu/index.d.ts.map +1 -0
  568. package/dist/ui/components/navigation-menu/index.js +7 -0
  569. package/dist/ui/components/navigation-menu/index.js.map +1 -0
  570. package/dist/ui/components/number-input/index.d.ts +5 -0
  571. package/dist/ui/components/number-input/index.d.ts.map +1 -0
  572. package/dist/ui/components/number-input/index.js +7 -0
  573. package/dist/ui/components/number-input/index.js.map +1 -0
  574. package/dist/ui/components/pagination/index.d.ts +5 -0
  575. package/dist/ui/components/pagination/index.d.ts.map +1 -0
  576. package/dist/ui/components/pagination/index.js +7 -0
  577. package/dist/ui/components/pagination/index.js.map +1 -0
  578. package/dist/ui/components/password-input/index.d.ts +5 -0
  579. package/dist/ui/components/password-input/index.d.ts.map +1 -0
  580. package/dist/ui/components/password-input/index.js +7 -0
  581. package/dist/ui/components/password-input/index.js.map +1 -0
  582. package/dist/ui/components/pin-input/index.d.ts +5 -0
  583. package/dist/ui/components/pin-input/index.d.ts.map +1 -0
  584. package/dist/ui/components/pin-input/index.js +7 -0
  585. package/dist/ui/components/pin-input/index.js.map +1 -0
  586. package/dist/ui/components/popover/index.d.ts +2 -0
  587. package/dist/ui/components/popover/index.d.ts.map +1 -0
  588. package/dist/ui/components/popover/index.js +2 -0
  589. package/dist/ui/components/popover/index.js.map +1 -0
  590. package/dist/ui/components/popover/popover.d.ts +14 -0
  591. package/dist/ui/components/popover/popover.d.ts.map +1 -0
  592. package/dist/ui/components/popover/popover.js +22 -0
  593. package/dist/ui/components/popover/popover.js.map +1 -0
  594. package/dist/ui/components/presence/index.d.ts +5 -0
  595. package/dist/ui/components/presence/index.d.ts.map +1 -0
  596. package/dist/ui/components/presence/index.js +7 -0
  597. package/dist/ui/components/presence/index.js.map +1 -0
  598. package/dist/ui/components/progress/index.d.ts +5 -0
  599. package/dist/ui/components/progress/index.d.ts.map +1 -0
  600. package/dist/ui/components/progress/index.js +7 -0
  601. package/dist/ui/components/progress/index.js.map +1 -0
  602. package/dist/ui/components/qr-code/index.d.ts +5 -0
  603. package/dist/ui/components/qr-code/index.d.ts.map +1 -0
  604. package/dist/ui/components/qr-code/index.js +7 -0
  605. package/dist/ui/components/qr-code/index.js.map +1 -0
  606. package/dist/ui/components/radio-group/index.d.ts +5 -0
  607. package/dist/ui/components/radio-group/index.d.ts.map +1 -0
  608. package/dist/ui/components/radio-group/index.js +7 -0
  609. package/dist/ui/components/radio-group/index.js.map +1 -0
  610. package/dist/ui/components/rating-group/index.d.ts +5 -0
  611. package/dist/ui/components/rating-group/index.d.ts.map +1 -0
  612. package/dist/ui/components/rating-group/index.js +7 -0
  613. package/dist/ui/components/rating-group/index.js.map +1 -0
  614. package/dist/ui/components/resize-handle/index.d.ts +2 -0
  615. package/dist/ui/components/resize-handle/index.d.ts.map +1 -0
  616. package/dist/ui/components/resize-handle/index.js +2 -0
  617. package/dist/ui/components/resize-handle/index.js.map +1 -0
  618. package/dist/ui/components/resize-handle/resize-handle.d.ts +39 -0
  619. package/dist/ui/components/resize-handle/resize-handle.d.ts.map +1 -0
  620. package/dist/ui/components/resize-handle/resize-handle.js +170 -0
  621. package/dist/ui/components/resize-handle/resize-handle.js.map +1 -0
  622. package/dist/ui/components/scroll-area/index.d.ts +5 -0
  623. package/dist/ui/components/scroll-area/index.d.ts.map +1 -0
  624. package/dist/ui/components/scroll-area/index.js +7 -0
  625. package/dist/ui/components/scroll-area/index.js.map +1 -0
  626. package/dist/ui/components/select/index.d.ts +2 -0
  627. package/dist/ui/components/select/index.d.ts.map +1 -0
  628. package/dist/ui/components/select/index.js +2 -0
  629. package/dist/ui/components/select/index.js.map +1 -0
  630. package/dist/ui/components/select/select.d.ts +40 -0
  631. package/dist/ui/components/select/select.d.ts.map +1 -0
  632. package/dist/ui/components/select/select.js +57 -0
  633. package/dist/ui/components/select/select.js.map +1 -0
  634. package/dist/ui/components/separator/index.d.ts +2 -0
  635. package/dist/ui/components/separator/index.d.ts.map +1 -0
  636. package/dist/ui/components/separator/index.js +2 -0
  637. package/dist/ui/components/separator/index.js.map +1 -0
  638. package/dist/ui/components/separator/separator.d.ts +9 -0
  639. package/dist/ui/components/separator/separator.d.ts.map +1 -0
  640. package/dist/ui/components/separator/separator.js +27 -0
  641. package/dist/ui/components/separator/separator.js.map +1 -0
  642. package/dist/ui/components/signature-pad/index.d.ts +5 -0
  643. package/dist/ui/components/signature-pad/index.d.ts.map +1 -0
  644. package/dist/ui/components/signature-pad/index.js +7 -0
  645. package/dist/ui/components/signature-pad/index.js.map +1 -0
  646. package/dist/ui/components/slider/index.d.ts +5 -0
  647. package/dist/ui/components/slider/index.d.ts.map +1 -0
  648. package/dist/ui/components/slider/index.js +7 -0
  649. package/dist/ui/components/slider/index.js.map +1 -0
  650. package/dist/ui/components/splitter/index.d.ts +5 -0
  651. package/dist/ui/components/splitter/index.d.ts.map +1 -0
  652. package/dist/ui/components/splitter/index.js +7 -0
  653. package/dist/ui/components/splitter/index.js.map +1 -0
  654. package/dist/ui/components/steps/index.d.ts +5 -0
  655. package/dist/ui/components/steps/index.d.ts.map +1 -0
  656. package/dist/ui/components/steps/index.js +7 -0
  657. package/dist/ui/components/steps/index.js.map +1 -0
  658. package/dist/ui/components/switch/index.d.ts +2 -0
  659. package/dist/ui/components/switch/index.d.ts.map +1 -0
  660. package/dist/ui/components/switch/index.js +2 -0
  661. package/dist/ui/components/switch/index.js.map +1 -0
  662. package/dist/ui/components/switch/switch.d.ts +48 -0
  663. package/dist/ui/components/switch/switch.d.ts.map +1 -0
  664. package/dist/ui/components/switch/switch.js +64 -0
  665. package/dist/ui/components/switch/switch.js.map +1 -0
  666. package/dist/ui/components/tabs/index.d.ts +2 -0
  667. package/dist/ui/components/tabs/index.d.ts.map +1 -0
  668. package/dist/ui/components/tabs/index.js +2 -0
  669. package/dist/ui/components/tabs/index.js.map +1 -0
  670. package/dist/ui/components/tabs/tabs.d.ts +22 -0
  671. package/dist/ui/components/tabs/tabs.d.ts.map +1 -0
  672. package/dist/ui/components/tabs/tabs.js +89 -0
  673. package/dist/ui/components/tabs/tabs.js.map +1 -0
  674. package/dist/ui/components/tags-input/index.d.ts +5 -0
  675. package/dist/ui/components/tags-input/index.d.ts.map +1 -0
  676. package/dist/ui/components/tags-input/index.js +7 -0
  677. package/dist/ui/components/tags-input/index.js.map +1 -0
  678. package/dist/ui/components/timer/index.d.ts +7 -0
  679. package/dist/ui/components/timer/index.d.ts.map +1 -0
  680. package/dist/ui/components/timer/index.js +8 -0
  681. package/dist/ui/components/timer/index.js.map +1 -0
  682. package/dist/ui/components/toast/index.d.ts +7 -0
  683. package/dist/ui/components/toast/index.d.ts.map +1 -0
  684. package/dist/ui/components/toast/index.js +8 -0
  685. package/dist/ui/components/toast/index.js.map +1 -0
  686. package/dist/ui/components/toc/index.d.ts +5 -0
  687. package/dist/ui/components/toc/index.d.ts.map +1 -0
  688. package/dist/ui/components/toc/index.js +7 -0
  689. package/dist/ui/components/toc/index.js.map +1 -0
  690. package/dist/ui/components/toggle/index.d.ts +5 -0
  691. package/dist/ui/components/toggle/index.d.ts.map +1 -0
  692. package/dist/ui/components/toggle/index.js +7 -0
  693. package/dist/ui/components/toggle/index.js.map +1 -0
  694. package/dist/ui/components/toggle-group/index.d.ts +5 -0
  695. package/dist/ui/components/toggle-group/index.d.ts.map +1 -0
  696. package/dist/ui/components/toggle-group/index.js +7 -0
  697. package/dist/ui/components/toggle-group/index.js.map +1 -0
  698. package/dist/ui/components/toolbar/index.d.ts +11 -0
  699. package/dist/ui/components/toolbar/index.d.ts.map +1 -0
  700. package/dist/ui/components/toolbar/index.js +18 -0
  701. package/dist/ui/components/toolbar/index.js.map +1 -0
  702. package/dist/ui/components/tooltip/index.d.ts +2 -0
  703. package/dist/ui/components/tooltip/index.d.ts.map +1 -0
  704. package/dist/ui/components/tooltip/index.js +2 -0
  705. package/dist/ui/components/tooltip/index.js.map +1 -0
  706. package/dist/ui/components/tooltip/tooltip.d.ts +14 -0
  707. package/dist/ui/components/tooltip/tooltip.d.ts.map +1 -0
  708. package/dist/ui/components/tooltip/tooltip.js +22 -0
  709. package/dist/ui/components/tooltip/tooltip.js.map +1 -0
  710. package/dist/ui/components/tour/index.d.ts +5 -0
  711. package/dist/ui/components/tour/index.d.ts.map +1 -0
  712. package/dist/ui/components/tour/index.js +7 -0
  713. package/dist/ui/components/tour/index.js.map +1 -0
  714. package/dist/ui/components/tree-view/index.d.ts +7 -0
  715. package/dist/ui/components/tree-view/index.d.ts.map +1 -0
  716. package/dist/ui/components/tree-view/index.js +8 -0
  717. package/dist/ui/components/tree-view/index.js.map +1 -0
  718. package/dist/ui/core/button-behavior.d.ts +3 -0
  719. package/dist/ui/core/button-behavior.d.ts.map +1 -0
  720. package/dist/ui/core/button-behavior.js +50 -0
  721. package/dist/ui/core/button-behavior.js.map +1 -0
  722. package/dist/ui/core/catalogue-element.d.ts +6 -0
  723. package/dist/ui/core/catalogue-element.d.ts.map +1 -0
  724. package/dist/ui/core/catalogue-element.js +28 -0
  725. package/dist/ui/core/catalogue-element.js.map +1 -0
  726. package/dist/ui/core/component-styles.d.ts +2 -0
  727. package/dist/ui/core/component-styles.d.ts.map +1 -0
  728. package/dist/ui/core/component-styles.js +77 -0
  729. package/dist/ui/core/component-styles.js.map +1 -0
  730. package/dist/ui/core/element.d.ts +12 -0
  731. package/dist/ui/core/element.d.ts.map +1 -0
  732. package/dist/ui/core/element.js +57 -0
  733. package/dist/ui/core/element.js.map +1 -0
  734. package/dist/ui/core/events.d.ts +6 -0
  735. package/dist/ui/core/events.d.ts.map +1 -0
  736. package/dist/ui/core/events.js +13 -0
  737. package/dist/ui/core/events.js.map +1 -0
  738. package/dist/ui/core/form-control.d.ts +4 -0
  739. package/dist/ui/core/form-control.d.ts.map +1 -0
  740. package/dist/ui/core/form-control.js +25 -0
  741. package/dist/ui/core/form-control.js.map +1 -0
  742. package/dist/ui/core/index.d.ts +5 -0
  743. package/dist/ui/core/index.d.ts.map +1 -0
  744. package/dist/ui/core/index.js +5 -0
  745. package/dist/ui/core/index.js.map +1 -0
  746. package/dist/ui/core/layout-styles.d.ts +2 -0
  747. package/dist/ui/core/layout-styles.d.ts.map +1 -0
  748. package/dist/ui/core/layout-styles.js +58 -0
  749. package/dist/ui/core/layout-styles.js.map +1 -0
  750. package/dist/ui/core/machine-checkpoints.d.ts +6 -0
  751. package/dist/ui/core/machine-checkpoints.d.ts.map +1 -0
  752. package/dist/ui/core/machine-checkpoints.js +47 -0
  753. package/dist/ui/core/machine-checkpoints.js.map +1 -0
  754. package/dist/ui/core/machine-clock.d.ts +16 -0
  755. package/dist/ui/core/machine-clock.d.ts.map +1 -0
  756. package/dist/ui/core/machine-clock.js +89 -0
  757. package/dist/ui/core/machine-clock.js.map +1 -0
  758. package/dist/ui/core/machine-codec.d.ts +29 -0
  759. package/dist/ui/core/machine-codec.d.ts.map +1 -0
  760. package/dist/ui/core/machine-codec.js +217 -0
  761. package/dist/ui/core/machine-codec.js.map +1 -0
  762. package/dist/ui/core/machine-profiles.d.ts +437 -0
  763. package/dist/ui/core/machine-profiles.d.ts.map +1 -0
  764. package/dist/ui/core/machine-profiles.js +1175 -0
  765. package/dist/ui/core/machine-profiles.js.map +1 -0
  766. package/dist/ui/core/machine-resources.d.ts +6 -0
  767. package/dist/ui/core/machine-resources.d.ts.map +1 -0
  768. package/dist/ui/core/machine-resources.js +46 -0
  769. package/dist/ui/core/machine-resources.js.map +1 -0
  770. package/dist/ui/core/machine.d.ts +29 -0
  771. package/dist/ui/core/machine.d.ts.map +1 -0
  772. package/dist/ui/core/machine.js +111 -0
  773. package/dist/ui/core/machine.js.map +1 -0
  774. package/dist/ui/core/parts.d.ts +4 -0
  775. package/dist/ui/core/parts.d.ts.map +1 -0
  776. package/dist/ui/core/parts.js +33 -0
  777. package/dist/ui/core/parts.js.map +1 -0
  778. package/dist/ui/core/portal.d.ts +11 -0
  779. package/dist/ui/core/portal.d.ts.map +1 -0
  780. package/dist/ui/core/portal.js +71 -0
  781. package/dist/ui/core/portal.js.map +1 -0
  782. package/dist/ui/core/public-machine.d.ts +4 -0
  783. package/dist/ui/core/public-machine.d.ts.map +1 -0
  784. package/dist/ui/core/public-machine.js +26 -0
  785. package/dist/ui/core/public-machine.js.map +1 -0
  786. package/dist/ui/core/resumable-machine.d.ts +13 -0
  787. package/dist/ui/core/resumable-machine.d.ts.map +1 -0
  788. package/dist/ui/core/resumable-machine.js +336 -0
  789. package/dist/ui/core/resumable-machine.js.map +1 -0
  790. package/dist/ui/drivers/bulma.d.ts +3 -0
  791. package/dist/ui/drivers/bulma.d.ts.map +1 -0
  792. package/dist/ui/drivers/bulma.js +249 -0
  793. package/dist/ui/drivers/bulma.js.map +1 -0
  794. package/dist/ui/drivers/daisyui.d.ts +9 -0
  795. package/dist/ui/drivers/daisyui.d.ts.map +1 -0
  796. package/dist/ui/drivers/daisyui.js +107 -0
  797. package/dist/ui/drivers/daisyui.js.map +1 -0
  798. package/dist/ui/drivers/index.d.ts +7 -0
  799. package/dist/ui/drivers/index.d.ts.map +1 -0
  800. package/dist/ui/drivers/index.js +7 -0
  801. package/dist/ui/drivers/index.js.map +1 -0
  802. package/dist/ui/drivers/registry.d.ts +11 -0
  803. package/dist/ui/drivers/registry.d.ts.map +1 -0
  804. package/dist/ui/drivers/registry.js +109 -0
  805. package/dist/ui/drivers/registry.js.map +1 -0
  806. package/dist/ui/drivers/shadcn.d.ts +3 -0
  807. package/dist/ui/drivers/shadcn.d.ts.map +1 -0
  808. package/dist/ui/drivers/shadcn.js +288 -0
  809. package/dist/ui/drivers/shadcn.js.map +1 -0
  810. package/dist/ui/drivers/types.d.ts +43 -0
  811. package/dist/ui/drivers/types.d.ts.map +1 -0
  812. package/dist/ui/drivers/types.js +2 -0
  813. package/dist/ui/drivers/types.js.map +1 -0
  814. package/dist/ui/drivers/unstyled.d.ts +3 -0
  815. package/dist/ui/drivers/unstyled.d.ts.map +1 -0
  816. package/dist/ui/drivers/unstyled.js +226 -0
  817. package/dist/ui/drivers/unstyled.js.map +1 -0
  818. package/dist/ui/engine.d.ts +24 -0
  819. package/dist/ui/engine.d.ts.map +1 -0
  820. package/dist/ui/engine.js +22 -0
  821. package/dist/ui/engine.js.map +1 -0
  822. package/dist/ui/index.d.ts +7 -0
  823. package/dist/ui/index.d.ts.map +1 -0
  824. package/dist/ui/index.js +6 -0
  825. package/dist/ui/index.js.map +1 -0
  826. package/dist/ui/machine-state.d.ts +349 -0
  827. package/dist/ui/machine-state.d.ts.map +1 -0
  828. package/dist/ui/machine-state.js +105 -0
  829. package/dist/ui/machine-state.js.map +1 -0
  830. package/dist/ui/presentation.d.ts +7 -0
  831. package/dist/ui/presentation.d.ts.map +1 -0
  832. package/dist/ui/presentation.js +21 -0
  833. package/dist/ui/presentation.js.map +1 -0
  834. package/dist/ui/render.d.ts +18 -0
  835. package/dist/ui/render.d.ts.map +1 -0
  836. package/dist/ui/render.js +31 -0
  837. package/dist/ui/render.js.map +1 -0
  838. package/dist/ui/resume.d.ts +28 -0
  839. package/dist/ui/resume.d.ts.map +1 -0
  840. package/dist/ui/resume.js +417 -0
  841. package/dist/ui/resume.js.map +1 -0
  842. package/dist/ui/server.d.ts +9 -0
  843. package/dist/ui/server.d.ts.map +1 -0
  844. package/dist/ui/server.js +6 -0
  845. package/dist/ui/server.js.map +1 -0
  846. package/dist/ui/state.d.ts +24 -0
  847. package/dist/ui/state.d.ts.map +1 -0
  848. package/dist/ui/state.js +64 -0
  849. package/dist/ui/state.js.map +1 -0
  850. package/dist/ui-server.d.ts +2 -0
  851. package/dist/ui-server.d.ts.map +1 -0
  852. package/dist/ui-server.js +2 -0
  853. package/dist/ui-server.js.map +1 -0
  854. package/dist/ui.d.ts +2 -0
  855. package/dist/ui.d.ts.map +1 -0
  856. package/dist/ui.js +2 -0
  857. package/dist/ui.js.map +1 -0
  858. package/dist/vite-environments.d.ts +27 -0
  859. package/dist/vite-environments.d.ts.map +1 -0
  860. package/dist/vite-environments.js +63 -0
  861. package/dist/vite-environments.js.map +1 -0
  862. package/dist/vite.d.ts +113 -3
  863. package/dist/vite.d.ts.map +1 -1
  864. package/dist/vite.js +1290 -196
  865. package/dist/vite.js.map +1 -1
  866. package/dist/workflow/browser.d.ts +7 -0
  867. package/dist/workflow/browser.d.ts.map +1 -0
  868. package/dist/workflow/browser.js +60 -0
  869. package/dist/workflow/browser.js.map +1 -0
  870. package/dist/workflow/compiler.d.ts +8 -0
  871. package/dist/workflow/compiler.d.ts.map +1 -0
  872. package/dist/workflow/compiler.js +122 -0
  873. package/dist/workflow/compiler.js.map +1 -0
  874. package/dist/workflow/http.d.ts +20 -0
  875. package/dist/workflow/http.d.ts.map +1 -0
  876. package/dist/workflow/http.js +68 -0
  877. package/dist/workflow/http.js.map +1 -0
  878. package/dist/workflow/index.d.ts +46 -0
  879. package/dist/workflow/index.d.ts.map +1 -0
  880. package/dist/workflow/index.js +91 -0
  881. package/dist/workflow/index.js.map +1 -0
  882. package/dist/workflow/journal.d.ts +9 -0
  883. package/dist/workflow/journal.d.ts.map +1 -0
  884. package/dist/workflow/journal.js +18 -0
  885. package/dist/workflow/journal.js.map +1 -0
  886. package/dist/workflow/node.d.ts +6 -0
  887. package/dist/workflow/node.d.ts.map +1 -0
  888. package/dist/workflow/node.js +24 -0
  889. package/dist/workflow/node.js.map +1 -0
  890. package/dist/workflow/operation.d.ts +23 -0
  891. package/dist/workflow/operation.d.ts.map +1 -0
  892. package/dist/workflow/operation.js +65 -0
  893. package/dist/workflow/operation.js.map +1 -0
  894. package/dist/workflow/protocol.d.ts +36 -0
  895. package/dist/workflow/protocol.d.ts.map +1 -0
  896. package/dist/workflow/protocol.js +45 -0
  897. package/dist/workflow/protocol.js.map +1 -0
  898. package/package.json +158 -27
  899. package/dist/create.d.ts +0 -21
  900. package/dist/create.d.ts.map +0 -1
  901. package/dist/create.js +0 -111
  902. package/dist/create.js.map +0 -1
  903. package/dist/runtime/atom.d.ts +0 -10
  904. package/dist/runtime/atom.d.ts.map +0 -1
  905. package/dist/runtime/atom.js +0 -38
  906. package/dist/runtime/atom.js.map +0 -1
  907. package/dist/ssr/node.d.ts +0 -3
  908. package/dist/ssr/node.d.ts.map +0 -1
  909. package/dist/ssr/node.js +0 -3
  910. package/dist/ssr/node.js.map +0 -1
  911. package/dist/ssr.d.ts +0 -4
  912. package/dist/ssr.d.ts.map +0 -1
  913. package/dist/ssr.js +0 -3
  914. package/dist/ssr.js.map +0 -1
  915. package/templates/basic/README.md +0 -18
  916. package/templates/basic/_gitignore +0 -3
  917. package/templates/basic/components/app-badge.html +0 -1
  918. package/templates/basic/index.html +0 -12
  919. package/templates/basic/islands/counter.ts +0 -13
  920. package/templates/basic/package.json +0 -26
  921. package/templates/basic/pages/about/index.html +0 -5
  922. package/templates/basic/pages/docs/index.md +0 -9
  923. package/templates/basic/pages/index.html +0 -9
  924. package/templates/basic/pages/layout.html +0 -8
  925. package/templates/basic/pnpm-workspace.yaml +0 -5
  926. package/templates/basic/server.mjs +0 -13
  927. package/templates/basic/style.css +0 -1
  928. package/templates/basic/tsconfig.json +0 -13
  929. package/templates/basic/vite.config.ts +0 -4
package/dist/vite.js CHANGED
@@ -1,29 +1,284 @@
1
+ import { inlineDocumentAssets } from "./compiler/inline-assets.js";
2
+ import { compileDataDocument } from './compiler/data-document.js';
3
+ import { parseRoutePolicy } from './compiler/route-policy.js';
4
+ import { extractPageScripts, compilePageScript } from "./compiler/page-scripts.js";
5
+ import { compileNativeScript } from "./compiler/native-scripts.js";
6
+ import { compileWorkflows, workflowPlugin } from "./workflow/compiler.js";
7
+ import { assertBrowserViewImport } from "./server-components/environment.js";
8
+ import { replaceClosures } from "./server-components/closures.js";
9
+ import { discoverViewReferences, browserReferencesCode } from "./server-components/references.js";
10
+ import { randomUUID } from "node:crypto";
11
+ import { compileFragment, compiledFragmentsPlugin } from "./server-components/compiler.js";
12
+ import { makeRouteMatches } from "./runtime/route-matches.js";
13
+ import { makeClientRouteMatcher } from "./runtime/client-routes.js";
14
+ import { errorHtml, notFoundHtml } from "./boundaries.js";
15
+ import { applyBaseToLinks, rewriteNavigationLinks } from "./compiler/base-links.js";
16
+ import { normalizeBase, routeKey, serverDataPrefix, serverDataUrl, stripBase, withBase } from "./route-path.js";
17
+ import { escapeAttribute, escapeText, inlineScript, jsonScript } from "./html-escape.js";
18
+ import { applyDocumentMetadata, applyGeneratorMetadata, pageHead, readDocumentHead } from "./compiler/metadata.js";
19
+ import * as Effect from "effect/Effect";
20
+ import { scanIslandModulesEffect } from "./compiler/island-modules.js";
1
21
  import { mkdir, readFile, readdir, rmdir, unlink, writeFile } from "node:fs/promises";
22
+ import { AsyncLocalStorage } from "node:async_hooks";
23
+ import { fileURLToPath } from "node:url";
24
+ import { readFileSync } from "node:fs";
2
25
  import path from "node:path";
3
- import { createServer } from "vite";
4
- import { compileProject } from "./compiler/index.js";
26
+ import { build as viteBuild, createServer } from "vite";
27
+ import { describeFindings, findInteractiveConstructs, projectImports } from "./compiler/static-analysis.js";
28
+ import { createRuntimes } from "./runtimes.js";
29
+ import { CompileCache, compilePlatformBlocks, compileProject } from "./compiler/index.js";
5
30
  import { compileIslands } from "./compiler/islands.js";
6
- import { createServerHandler } from "./server.js";
31
+ import { createServerHandler, isServerData } from "./server.js";
32
+ import { findServerModules } from "./compiler/server-modules.js";
33
+ import { findApiRoutes } from "./compiler/api-routes.js";
34
+ import { toWebRequest, writeWebResponse } from "./server/node.js";
35
+ import { routeTypes } from "./runtime/href.js";
36
+ import { writeElectronScaffold } from "./electron.js";
37
+ import { createEnvironmentModuleRuntime, detectViteEnvironmentApi, invalidateEnvironmentModule, normalizeEnvironmentConfiguration } from "./vite-environments.js";
7
38
  const virtualId = "virtual:fuzor/client";
39
+ const rendererModules = {
40
+ "virtual:fuzor/compiler/react": 'export { createElement } from "react"; export { renderToString, renderToStaticMarkup } from "react-dom/server";',
41
+ "virtual:fuzor/compiler/vue": 'export { createSSRApp } from "vue"; export { renderToString } from "vue/server-renderer";',
42
+ "virtual:fuzor/compiler/solid": 'export { createComponent } from "solid-js"; export { renderToString, generateHydrationScript } from "solid-js/web";'
43
+ };
8
44
  const resolvedVirtualId = `\0${virtualId}`;
9
45
  const outletStart = "<!--fuzor:outlet-start-->";
10
46
  const outletEnd = "<!--fuzor:outlet-end-->";
11
- function escapeAttribute(value) {
12
- return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;");
47
+ function findRoute(project, pathname) {
48
+ const key = routeKey(pathname);
49
+ return key === undefined ? undefined : project.routes.find((entry) => entry.path === key);
13
50
  }
14
- function routeContent(project, pathname) {
15
- const normalized = pathname === "/" ? "/" : `${pathname.replace(/\/+$/, "")}/`;
16
- const route = project.routes.find((entry) => entry.path === normalized);
17
- if (!route)
18
- throw new Error(`No Fuzor route for ${normalized}`);
19
- return route.html;
51
+ function boundaryFor(project, kind, scope) {
52
+ return project.boundaries?.find(boundary => boundary.kind === kind && boundary.scope === scope);
20
53
  }
21
- function outletFor(project, target, pathname) {
54
+ /** Boundary pages by scope, always including a root page (the author's or Fuzor's default). */
55
+ function boundaryPages(project, kind, fallback) {
56
+ const pages = new Map();
57
+ const title = kind === "not-found" ? "Page not found" : "Something went wrong";
58
+ pages.set("/", { html: fallback, metadata: { title } });
59
+ for (const boundary of project.boundaries ?? []) {
60
+ if (boundary.kind === kind)
61
+ pages.set(boundary.scope, { html: boundary.html, metadata: { title, ...boundary.metadata } });
62
+ }
63
+ return pages;
64
+ }
65
+ function paramsAttribute(params) {
66
+ return params ? ` data-fuzor-params="${escapeAttribute(JSON.stringify(params))}"` : "";
67
+ }
68
+ function routeAttributes(route, base) {
69
+ return `${paramsAttribute(route.params)}${route.pattern || route.requestPattern ? ` data-fuzor-pattern="${escapeAttribute(route.pattern ?? route.path)}"` : ""}${route.requestPattern ? ` data-fuzor-request-pattern="${escapeAttribute(route.requestPattern)}"` : ""}${route.serverData ? ` data-fuzor-data="${escapeAttribute(serverDataUrl(route.path, base))}"` : ""}`;
70
+ }
71
+ function outletFor(project, target, pathname, fallbacks, mixed = false) {
72
+ const current = findRoute(project, pathname);
73
+ if (mixed) {
74
+ target = current?.policy?.navigation === "spa" ? "spa" : "mpa";
75
+ if (target === "spa")
76
+ project = { ...project, routes: project.routes.filter(route => route.policy?.navigation === "spa" && route.policy.spaScope === current?.policy?.spaScope) };
77
+ }
22
78
  if (target !== "spa") {
23
- return `<fuzor-router>${routeContent(project, pathname)}</fuzor-router>`;
79
+ const route = findRoute(project, pathname);
80
+ if (!route)
81
+ throw new Error(`No Fuzor route for ${pathname}`);
82
+ return `<fuzor-router data-fuzor-navigation="document"${routeAttributes(route, fallbacks.base)}>${route.html}</fuzor-router>`;
83
+ }
84
+ const initial = findRoute(project, pathname);
85
+ const outlet = initial
86
+ ? `<fuzor-router data-fuzor-navigation="spa" data-fuzor-initial-route="${escapeAttribute(initial.path)}"${routeAttributes(initial, fallbacks.base)}>${initial.html}</fuzor-router>`
87
+ : `<fuzor-router></fuzor-router>`;
88
+ const templates = project.routes.map((route) => `<template data-fuzor-route="${escapeAttribute(route.path)}"${routeAttributes(route, fallbacks.base)}>${route.html}</template>`).join("\n");
89
+ // "" holds the shell defaults, because the shared document's head already shows the first page's metadata.
90
+ const metadata = { "": fallbacks.head, ...Object.fromEntries(project.routes.map(route => [route.path, route.metadata ?? {}])) };
91
+ const boundaries = [];
92
+ for (const [kind, fallback] of [["not-found", fallbacks.notFound], ["error", fallbacks.error]]) {
93
+ for (const [scope, page] of boundaryPages(project, kind, fallback)) {
94
+ boundaries.push(`<template data-fuzor-${kind}="${escapeAttribute(scope)}">${page.html}</template>`);
95
+ metadata[`${kind}:${scope}`] = page.metadata;
96
+ }
97
+ }
98
+ const redirects = project.redirects ? `\n<script type="application/json" data-fuzor-redirects>${jsonScript(project.redirects)}</script>` : "";
99
+ return `${outlet}\n${templates}\n${boundaries.join("\n")}\n<script type="application/json" data-fuzor-metadata>${jsonScript(metadata)}</script>${redirects}`;
100
+ }
101
+ /** Bundle the parser-time selector without the asynchronous application runtime. */
102
+ async function inlineInitialRouteScript(options) {
103
+ const source = fileURLToPath(new URL(`./runtime/initial-route.${import.meta.url.endsWith(".ts") ? "ts" : "js"}`, import.meta.url));
104
+ const result = await viteBuild({
105
+ configFile: false, publicDir: false, logLevel: "silent",
106
+ build: { write: false, minify: true, lib: { entry: source, name: "fuzorInitial", formats: ["iife"] } }
107
+ });
108
+ const output = (Array.isArray(result) ? result[0] : result);
109
+ const code = output.output.find(item => item.type === "chunk")?.code;
110
+ if (!code)
111
+ throw new Error("Fuzor initial route selector could not be bundled");
112
+ return `<script>${inlineScript(`(()=>{${code}\nfuzorInitial.selectInitialRoute(window,${jsonScript(options)});})();`)}</script>`;
113
+ }
114
+ /** Finished documents for a server: nothing is assembled per request. */
115
+ /** Island names in a document: hosts and `client:none` markers. */
116
+ export function documentIslands(html) {
117
+ const names = new Set();
118
+ for (const match of html.matchAll(/<fuzor-island\b[^>]*?\ssrc="([^"]+)"/g))
119
+ names.add(match[1]);
120
+ for (const match of html.matchAll(/<!--fuzor:static ([^\s]+?)-->/g))
121
+ names.add(match[1]);
122
+ return names;
123
+ }
124
+ /**
125
+ * Links the stylesheets of every island in a document, so prerendered previews and client:none components are
126
+ * styled at first paint instead of when their JavaScript loads. Links from a template are replaced, not added to.
127
+ */
128
+ export function withIslandStyles(html, styles, base) {
129
+ const stripped = html.replace(/<link rel="stylesheet" href="[^"]*" data-fuzor-island-css>/g, "");
130
+ const files = [...new Set([...documentIslands(stripped)].flatMap(name => styles[name] ?? styles["island:" + name] ?? []))]
131
+ .map(file => `${base.endsWith("/") ? base : `${base}/`}${file}`)
132
+ .filter(href => !stripped.includes(`href="${href}"`));
133
+ if (!files.length)
134
+ return stripped;
135
+ return stripped.replace("</head>", () => `${files.map(href => `<link rel="stylesheet" href="${escapeAttribute(href)}" data-fuzor-island-css>`).join("")}</head>`);
136
+ }
137
+ function serverManifest(project, target, template, base, fallbacks, finish = html => html, clientRoutes, assetDirectory, mixed = false) {
138
+ const boundaryDocuments = (kind, fallback) => Object.fromEntries([...boundaryPages(project, kind, fallback)].map(([scope, page]) => [scope, finish(applyDocumentMetadata(replaceOutlet(template, `<fuzor-router data-fuzor-${kind}="${escapeAttribute(scope)}">${page.html}</fuzor-router>`), pageHead(fallbacks.head, page.metadata)))]));
139
+ const notFoundDocuments = boundaryDocuments("not-found", fallbacks.notFound);
140
+ const revalidate = Object.fromEntries(project.routes.flatMap(route => route.metadata?.revalidate === undefined ? [] : [[route.path, route.metadata.revalidate]]));
141
+ const shared = {
142
+ ...(Object.keys(revalidate).length ? { revalidate } : {}),
143
+ ...(project.redirects ? { redirects: project.redirects } : {}),
144
+ requestPatterns: Object.fromEntries(project.routes.filter(route => route.requestPattern).map(route => [route.requestPattern, route.path])),
145
+ routePolicies: Object.fromEntries(project.routes.map(route => [route.path, route.policy ?? { rendering: "static", navigation: target === "spa" ? "spa" : "document" }])),
146
+ notFoundDocument: notFoundDocuments["/"],
147
+ ...(Object.keys(notFoundDocuments).length > 1 ? { notFoundDocuments } : {}),
148
+ errorDocument: boundaryDocuments("error", fallbacks.error)["/"],
149
+ ...(base === "/" ? {} : { base })
150
+ };
151
+ const manifest = target === "spa"
152
+ ? { document: finish(template), routeDocuments: Object.fromEntries(project.routes.map(route => [route.path, finish(applyDocumentMetadata(replaceOutlet(template, outletFor(project, "spa", route.path, fallbacks)), pageHead(fallbacks.head, route.metadata ?? {})))])), routes: Object.fromEntries(project.routes.map((route) => [route.path, true])), ...(clientRoutes ? { clientRoutes, ...(assetDirectory ? { assetDirectory } : {}) } : {}), ...shared }
153
+ : { documents: Object.fromEntries(project.routes.map((route) => [route.path, finish(applyDocumentMetadata(replaceOutlet(template, outletFor(project, "mpa", route.path, fallbacks, mixed)), pageHead(fallbacks.head, route.metadata ?? {})))])), ...shared };
154
+ const documents = "documents" in manifest ? manifest.documents : manifest.routeDocuments ?? {};
155
+ return { ...manifest, dataBindings: Object.fromEntries(project.routes.filter(route => route.policy?.rendering === "request").map(route => [route.path, compileDataDocument(documents[route.path])])) };
156
+ }
157
+ /** Loads each page's `server.ts` default export and checks it was declared with `defineServerData`. */
158
+ async function loadRouteDataModules(project, load, root) {
159
+ const data = {};
160
+ for (const route of project.routes) {
161
+ if (!route.serverData)
162
+ continue;
163
+ const module = await load(route.serverData);
164
+ if (!isServerData(module.default)) {
165
+ throw new Error(`${path.relative(root, route.serverData)} must export default defineServerData(...) from "fuzor/server".`);
166
+ }
167
+ data[route.path] = { data: module.default, ...(route.params ? { params: route.params } : {}) };
168
+ }
169
+ return data;
170
+ }
171
+ /** Static hosts cannot send 308s from HTML: a refresh document works everywhere, `_redirects` on hosts that read it. */
172
+ function redirectDocument(destination) {
173
+ const target = escapeAttribute(destination);
174
+ return `<!doctype html>\n<html lang="en"><head><meta charset="utf-8"><title>Redirecting…</title><meta name="robots" content="noindex"><meta http-equiv="refresh" content="0; url=${target}"><link rel="canonical" href="${target}"></head><body><p>This page has moved to <a href="${target}">${escapeText(destination)}</a>.</p></body></html>\n`;
175
+ }
176
+ async function loadApiModules(files, load) {
177
+ return Promise.all(files.map(async (route) => ({ pattern: route.pattern, segments: route.segments, source: route.relative, module: await load(route.file) })));
178
+ }
179
+ /**
180
+ * Cloudflare Workers output: static assets serve every prerendered page, `_redirects` and 404 pages, while
181
+ * only API endpoints and server data run the Worker. Deploy with `wrangler deploy --config <dir>/wrangler.jsonc`.
182
+ */
183
+ async function writeCloudflareOutput(directory, root, target, base, clientDirectory, requestRoutes, assetReference) {
184
+ const packageName = await readFile(path.join(root, "package.json"), "utf8").then(text => JSON.parse(text).name, () => undefined);
185
+ const name = (packageName ?? path.basename(root)).replace(/^@[^/]+\//, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63) || "fuzor-app";
186
+ await mkdir(path.join(directory, "cloudflare"), { recursive: true });
187
+ await writeFile(path.join(directory, "cloudflare/worker.mjs"), [
188
+ "// Generated by Fuzor. Static assets answer page requests; this Worker answers API and server data requests.",
189
+ 'import { handler } from "../entry.mjs";',
190
+ "",
191
+ "export default {",
192
+ " fetch(request) {",
193
+ " return handler(request);",
194
+ " }",
195
+ "};",
196
+ ""
197
+ ].join("\n"), "utf8");
198
+ const prefix = base === "/" ? "" : base.slice(0, -1);
199
+ const config = {
200
+ $schema: "../node_modules/wrangler/config-schema.json",
201
+ name,
202
+ main: "cloudflare/worker.mjs",
203
+ compatibility_date: "2026-09-01",
204
+ assets: {
205
+ directory: assetReference,
206
+ binding: "ASSETS",
207
+ not_found_handling: target === "spa" ? "single-page-application" : "404-page",
208
+ run_worker_first: [...new Set([`${prefix}/api`, `${prefix}/api/*`, `${prefix}/_fuzor/data/*`, `${prefix}/_fuzor/render`, ...requestRoutes.map(route => withBase(route, base)), ...requestRoutes.map(route => withBase(route.replace(/\/$/, ""), base))])]
209
+ }
210
+ };
211
+ await writeFile(path.join(directory, "wrangler.jsonc"), `// Generated by Fuzor on each build; copy it next to your project to customize.\n${JSON.stringify(config, null, 2)}\n`, "utf8");
212
+ await writeFile(path.join(clientDirectory, ".assetsignore"), ".fuzor-assets.json\n", "utf8");
213
+ }
214
+ /**
215
+ * Build-time previews and browser hydration must use the same framework version. React ships its server
216
+ * renderer in react-dom, a separate package, so a version mismatch between react and react-dom is an error.
217
+ */
218
+ export function checkRendererVersions(root, islands, runtimes = {}) {
219
+ for (const [key, packages] of Object.entries(runtimes)) {
220
+ if (!packages.react || !islands.some(island => island.file.includes(`.${key}.`)))
221
+ continue;
222
+ if (!packages["react-dom"])
223
+ throw new Error(`Runtime ${key} maps react but not react-dom; React islands render and hydrate with both.`);
224
+ checkPair(root, packages.react, packages["react-dom"], key);
24
225
  }
25
- const templates = project.routes.map((route) => `<template data-fuzor-route="${escapeAttribute(route.path)}">${route.html}</template>`).join("\n");
26
- return `<fuzor-router></fuzor-router>\n${templates}`;
226
+ if (!islands.some(island => /\.react\.[jt]sx$/.test(island.file)))
227
+ return;
228
+ checkPair(root, "react", "react-dom");
229
+ }
230
+ function checkPair(root, reactName, domName, runtime) {
231
+ // Walk node_modules directories like Vite's resolver; NODE_PATH (set by pnpm scripts) must not count.
232
+ const version = (name) => {
233
+ for (let directory = path.resolve(root);; directory = path.dirname(directory)) {
234
+ try {
235
+ return JSON.parse(readFileSync(path.join(directory, "node_modules", name, "package.json"), "utf8")).version;
236
+ }
237
+ catch { }
238
+ if (path.dirname(directory) === directory)
239
+ return undefined;
240
+ }
241
+ };
242
+ const react = version(reactName);
243
+ const dom = version(domName);
244
+ const label = runtime ? `Runtime ${runtime} islands` : "React islands";
245
+ if (!react || !dom)
246
+ throw new Error(`${label} need both ${reactName} and ${domName} installed (found ${reactName} ${react ?? "missing"}, ${domName} ${dom ?? "missing"}).`);
247
+ if (react !== dom)
248
+ throw new Error(`${label} render at build time with ${domName} ${dom} and hydrate with ${reactName} ${react}. Install the same version of both packages.`);
249
+ }
250
+ /** Adds Vite's `id`, `loc` and `frame` to compiler errors so the overlay and build output point at the file. */
251
+ async function withViteLocation(error) {
252
+ const location = error?.location;
253
+ if (!location || !(error instanceof Error))
254
+ return error;
255
+ const extra = { id: location.file };
256
+ const line = location.line;
257
+ if (line !== undefined) {
258
+ extra.loc = { file: location.file, line, column: location.column ?? 1 };
259
+ const lines = await readFile(location.file, "utf8").then(text => text.split("\n"), () => []);
260
+ if (lines.length) {
261
+ const first = Math.max(1, line - 2);
262
+ extra.frame = lines.slice(first - 1, line + 2).map((text, index) => {
263
+ const number = first + index;
264
+ const gutter = `${number === line ? ">" : " "} ${String(number).padStart(String(line + 2).length)} | `;
265
+ return number === line ? `${gutter}${text}\n${" ".repeat(gutter.length + (location.column ?? 1) - 1)}^` : `${gutter}${text}`;
266
+ }).join("\n");
267
+ }
268
+ }
269
+ return Object.assign(error, extra);
270
+ }
271
+ function searchIndex(project, option) {
272
+ if (!option)
273
+ return undefined;
274
+ const scope = typeof option === "object" && option.scope ? routeKey(option.scope) ?? "/" : "/";
275
+ const documents = project.routes.filter(route => route.path.startsWith(scope) && route.search).map(route => ({
276
+ path: route.path,
277
+ title: route.metadata?.navTitle ?? route.search.headings[0] ?? route.metadata?.title ?? route.path,
278
+ headings: route.search.headings.slice(1),
279
+ text: route.search.text
280
+ }));
281
+ return JSON.stringify({ version: 1, documents });
27
282
  }
28
283
  function replaceOutlet(document, content) {
29
284
  const start = document.indexOf(outletStart);
@@ -32,287 +287,1126 @@ function replaceOutlet(document, content) {
32
287
  throw new Error(`index.html must contain ${outletStart} and ${outletEnd}.`);
33
288
  return document.slice(0, start + outletStart.length) + content + document.slice(end);
34
289
  }
35
- export function fuzorPlugin(options = {}) {
36
- const selectedTarget = options.target ?? (process.env.FUZOR_TARGET === "mpa" || process.env.FUZOR_TARGET === "ssr" ? process.env.FUZOR_TARGET : "spa");
37
- const legacySsr = selectedTarget === "ssr";
38
- const target = legacySsr ? "mpa" : selectedTarget;
39
- const withServer = legacySsr || (options.server ?? process.env.FUZOR_SERVER === "1");
40
- const inline = options.inline ?? process.env.FUZOR_INLINE === "1";
41
- if (inline && withServer)
290
+ function serverViewDocument(html) {
291
+ let found = false;
292
+ const document = html.replace(/(<fuzor-router\b[^>]*>)[\s\S]*?<\/fuzor-router>/, (_match, open) => { found = true; return open + "<!--fuzor-view--></fuzor-router>"; });
293
+ if (!found || !document.includes("</body>"))
294
+ throw new Error("Server views require a compiled outlet and a document body.");
295
+ return document.replace("</body>", "<!--fuzor-snapshot--></body>");
296
+ }
297
+ /**
298
+ * The plugin creates private Vite servers to load island and `paths` modules. Their config file loads
299
+ * this plugin again; those nested instances only provide virtual modules and never compile the project.
300
+ */
301
+ const nestedServer = new AsyncLocalStorage();
302
+ /**
303
+ * Vite servers Fuzor starts inside a dev server or build to load pages' modules and analyze islands. They must not
304
+ * open an HMR WebSocket (two would compete for its port, and a failed one never closes) and must not share the
305
+ * dev server's dependency cache (each would re-optimize and invalidate the other's pre-bundled files).
306
+ */
307
+ export function nestedServerConfig(config) {
308
+ return {
309
+ root: config.root,
310
+ configFile: config.configFile ?? false,
311
+ plugins: [workflowPlugin(), {
312
+ name: "fuzor:nested-renderers",
313
+ resolveId(id) { if (Object.hasOwn(rendererModules, id))
314
+ return `\0${id}`; },
315
+ load(id) { if (id.startsWith("\0") && Object.hasOwn(rendererModules, id.slice(1)))
316
+ return rendererModules[id.slice(1)]; }
317
+ }],
318
+ server: { middlewareMode: true, hmr: false, ws: false },
319
+ cacheDir: path.join(config.cacheDir, "fuzor-nested"),
320
+ optimizeDeps: { noDiscovery: true, include: [] },
321
+ appType: "custom"
322
+ };
323
+ }
324
+ /**
325
+ * Resolves the build profile. Sources, highest first: explicit `fuzorPlugin()` options, the `FUZOR_TARGET`,
326
+ * `FUZOR_SERVER` and `FUZOR_INLINE` environment variables (which the CLI flags set), then defaults
327
+ * (`spa`, static, not inline). A plugin option and a different environment value is a configuration
328
+ * error rather than a silent override, because the CLI flag would otherwise be ignored.
329
+ */
330
+ export function resolveFuzorProfile(options = {}, env = process.env, serverModules = []) {
331
+ const flag = (name) => {
332
+ const value = env[name]?.trim().toLowerCase();
333
+ if (value === undefined || value === "")
334
+ return undefined;
335
+ if (value === "1" || value === "true")
336
+ return true;
337
+ if (value === "0" || value === "false")
338
+ return false;
339
+ throw new Error(`${name} must be 1, 0, true or false; received ${JSON.stringify(env[name])}.`);
340
+ };
341
+ if (options.navigation !== undefined && !["auto", "navigation-api", "embedded"].includes(options.navigation)) {
342
+ throw new Error(`fuzorPlugin({ navigation }) must be "auto", "navigation-api" or "embedded"; received ${JSON.stringify(options.navigation)}.`);
343
+ }
344
+ const envTarget = env.FUZOR_TARGET?.trim() || undefined;
345
+ if (envTarget !== undefined && envTarget !== "spa" && envTarget !== "mpa" && envTarget !== "electron") {
346
+ throw new Error(`Unknown Fuzor navigation target in FUZOR_TARGET: ${envTarget}. Choose spa, mpa or electron.`);
347
+ }
348
+ const envServer = flag("FUZOR_SERVER");
349
+ const envInline = flag("FUZOR_INLINE");
350
+ const envElectron = flag("FUZOR_ELECTRON");
351
+ const envPlatform = env.FUZOR_PLATFORM?.trim() || undefined;
352
+ const platform = options.platform ?? envPlatform ?? (envTarget === "electron" ? "desktop" : "web");
353
+ if (!/^[a-z][a-z0-9-]*$/.test(platform))
354
+ throw new Error(`Invalid Fuzor platform ${JSON.stringify(platform)}. Use lowercase letters, digits and hyphens.`);
355
+ if (options.platform !== undefined && envPlatform !== undefined && options.platform !== envPlatform) {
356
+ throw new Error(`fuzorPlugin({ platform: ${JSON.stringify(options.platform)} }) conflicts with FUZOR_PLATFORM=${JSON.stringify(envPlatform)}.`);
357
+ }
358
+ const envAdapter = env.FUZOR_ADAPTER?.trim() || undefined;
359
+ for (const [label, value] of [["fuzorPlugin({ adapter })", options.adapter], ["FUZOR_ADAPTER", envAdapter]]) {
360
+ if (value !== undefined && value !== "node" && value !== "cloudflare")
361
+ throw new Error(`Unknown Fuzor adapter in ${label}: ${value}. Choose node or cloudflare.`);
362
+ }
363
+ if (options.adapter !== undefined && envAdapter !== undefined && options.adapter !== envAdapter) {
364
+ throw new Error(`fuzorPlugin({ adapter: ${JSON.stringify(options.adapter)} }) conflicts with FUZOR_ADAPTER=${JSON.stringify(envAdapter)} (set by a CLI flag or the environment). Remove one of them.`);
365
+ }
366
+ const adapter = (options.adapter ?? envAdapter ?? "node");
367
+ const conflict = (option, optionValue, variable, envValue) => {
368
+ if (optionValue !== undefined && envValue !== undefined && optionValue !== envValue) {
369
+ throw new Error(`fuzorPlugin({ ${option}: ${JSON.stringify(optionValue)} }) conflicts with ${variable}=${JSON.stringify(envValue)} (set by a CLI flag or the environment). Remove one of them.`);
370
+ }
371
+ };
372
+ // The CLI always states server/inline explicitly; only an enabled flag can contradict a plugin option.
373
+ if (envServer)
374
+ conflict("server", options.server, "FUZOR_SERVER", envServer);
375
+ if (envInline)
376
+ conflict("inline", options.inline, "FUZOR_INLINE", envInline);
377
+ const packaged = ["desktop", "ios", "android"].includes(platform);
378
+ const requestedTarget = envTarget ?? (envInline || options.inline || packaged ? "spa" : "mpa");
379
+ const mixed = envTarget === undefined && !envInline && !options.inline && !packaged;
380
+ const electron = options.electron ?? envElectron ?? requestedTarget === "electron";
381
+ const target = (requestedTarget === "electron" ? "spa" : requestedTarget);
382
+ const serverReasons = serverModules.map(file => file.startsWith("api/") ? `${file} defines an API endpoint` : file.endsWith(".html") ? `${file} declares request rendering` : `${file} defines server data`);
383
+ if (options.serverComponents) {
384
+ makeClientRouteMatcher(Object.fromEntries(options.serverComponents.routes.map(route => [route, "/"])));
385
+ for (const entry of [options.serverComponents.server, options.serverComponents.client, options.serverComponents.references].filter((value) => value !== undefined)) {
386
+ if (!entry || path.isAbsolute(entry) || entry.split(/[\\/]/).includes(".."))
387
+ throw new Error("Server component entries must be paths inside the project.");
388
+ }
389
+ if (!options.serverComponents.client && !options.serverComponents.references)
390
+ throw new Error("Server components require a client entry or generated reference directory.");
391
+ if (!options.serverComponents.routes.length)
392
+ throw new Error("Server components need at least one route.");
393
+ if (options.navigation === "embedded")
394
+ throw new Error("Server components require HTTP navigation.");
395
+ serverReasons.push(`${options.serverComponents.server} defines server components`);
396
+ }
397
+ const inline = electron || packaged ? true : options.inline ?? envInline ?? false;
398
+ if (inline && target !== "spa")
399
+ throw new Error("Inline output is only supported for the SPA target.");
400
+ if (electron && target !== "spa")
401
+ throw new Error("Electron output is only supported for the SPA target.");
402
+ if (serverReasons.length) {
403
+ const needs = `This app needs server output because ${serverReasons.join("; ")}.`;
404
+ if (inline)
405
+ throw new Error(`${needs} Inline SPA output is a static single file and cannot answer data requests; remove --inline.`);
406
+ if (options.server === false)
407
+ throw new Error(`${needs} Remove server: false from fuzorPlugin().`);
408
+ if (envServer === false)
409
+ throw new Error(`${needs} Unset FUZOR_SERVER=0.`);
410
+ }
411
+ if (adapter === "cloudflare" && inline)
412
+ throw new Error("The cloudflare adapter builds a Worker and cannot be combined with inline output.");
413
+ if (adapter === "cloudflare" && options.server === false)
414
+ throw new Error("The cloudflare adapter implies server output; remove server: false.");
415
+ const server = serverReasons.length > 0 || adapter === "cloudflare" || (options.server ?? envServer ?? false);
416
+ if (inline && server)
42
417
  throw new Error("SPA inline output cannot be combined with server output.");
43
- const serverOutDir = legacySsr ? "dist-ssr/client" : `dist-${target}-server/client`;
418
+ return { target, mixed, backendOutDir: ".fuzor/dist-backend", platform, server, inline, outDir: electron ? ".fuzor/dist-desktop" : platform !== "web" ? `.fuzor/dist-${platform}` : mixed ? ".fuzor/web/dist" : `.fuzor/web/dist-${target}`, serverReasons, adapter, ...(electron ? { electron: true } : {}) };
419
+ }
420
+ export function fuzorPlugin(options = {}) {
421
+ const nested = nestedServer.getStore() === true;
422
+ let viewBuildId = randomUUID();
423
+ let referencesPromise;
424
+ const references = () => referencesPromise ??= discoverViewReferences(vite.root, options.serverComponents.references);
425
+ const referenceStub = (file, refs) => {
426
+ const relative = path.relative(vite.root, file).split(path.sep).join("/");
427
+ const client = refs.clients.find(ref => ref.file === relative);
428
+ if (client)
429
+ return `export default ${JSON.stringify({ id: client.id })};`;
430
+ const closures = refs.closures.filter(ref => ref.file === relative);
431
+ if (closures.length)
432
+ return readFile(file, "utf8").then(code => replaceClosures(code, closures));
433
+ const handlers = refs.handlers.filter(ref => ref.file === relative);
434
+ return handlers.length ? handlers.map(ref => `export const ${ref.name}=${JSON.stringify({ id: ref.id })};`).join("\n") : undefined;
435
+ };
436
+ const generatedViews = async (views) => {
437
+ if (!options.serverComponents?.references)
438
+ return views;
439
+ const refs = await references();
440
+ return { ...views, manifest: { buildId: viewBuildId, templates: refs.templates }, components: refs.clients.map(ref => ref.id), handlers: [...refs.handlers.map(ref => ref.id), ...refs.closures.map(ref => ref.id)] };
441
+ };
442
+ const configuredEnvironments = normalizeEnvironmentConfiguration(options.experimental?.environments);
443
+ const environmentNames = {
444
+ client: configuredEnvironments.client ?? "client",
445
+ server: configuredEnvironments.server ?? "server",
446
+ edge: configuredEnvironments.edge ?? "edge"
447
+ };
448
+ const environmentApiEnabled = Object.keys(configuredEnvironments).length > 0;
449
+ const moduleEnvironment = options.experimental?.runtime === "edge" ? environmentNames.edge : environmentNames.server;
450
+ // Validated immediately for early errors; server data detection refines it once the root is known.
451
+ let profile = resolveFuzorProfile(options);
452
+ let { target, inline } = profile;
453
+ let withServer = profile.server;
454
+ let serverModuleFiles = [];
455
+ let apiFiles = [];
456
+ /**
457
+ * Development CSS arrives through module imports; client:none components have none, so documents import them
458
+ * for their styles. Production builds link the extracted stylesheets instead.
459
+ */
460
+ const withStaticModuleImports = (html) => {
461
+ const withoutPrevious = html.replace(/<script type="module" data-fuzor-static-css>.*?<\/script>/g, "");
462
+ const files = [...withoutPrevious.matchAll(/<!--fuzor:static ([^\s]+?)-->/g)].flatMap(match => islands.filter(island => island.name === match[1]).map(island => island.file));
463
+ return files.length ? withoutPrevious.replace("</head>", () => `<script type="module" data-fuzor-static-css>${[...new Set(files)].map(file => `import ${JSON.stringify(file)};`).join("")}</script></head>`) : withoutPrevious;
464
+ };
465
+ let buildFailed = false;
466
+ /** Stylesheets each island loads, from the client bundle. */
467
+ let islandStyles = {};
468
+ let bundleWritten = false;
44
469
  let vite;
470
+ let environmentCapability = { supported: false, reason: "legacy" };
471
+ const environmentState = new Map();
472
+ let releaseRuntimeHooks = () => { };
473
+ let runtimes;
474
+ /** Runtime copies of framework adapters and renderers, by resolved module ID. */
475
+ const runtimeModules = new Map();
476
+ /** Path deployment base from Vite's `base`; relative and absolute-URL bases leave routes at `/`. */
477
+ let pathBase = "/";
478
+ /** The shell's own head, read before any page metadata is applied to it. */
479
+ let shellHead = {};
480
+ const fallbacks = () => ({ notFound: applyBaseToLinks(notFoundHtml, pathBase), error: applyBaseToLinks(errorHtml, pathBase), base: pathBase, head: shellHead });
45
481
  let project;
482
+ let pageScripts = [];
483
+ const nativeHandlers = new Map();
484
+ let inlineModuleFiles = [];
485
+ let scriptRoutes = [];
486
+ const routeScriptId = (route) => `virtual:fuzor/route-client/${encodeURIComponent(route.path)}/${route.path === "/" ? "index" : route.path.split("/").filter(Boolean).join("-").replace(/[^a-zA-Z0-9_-]/g, "_")}-client.js`;
487
+ const pageScriptId = (script) => `virtual:fuzor/page-script/${script.id}.js`;
488
+ let revision = 0;
489
+ let compilation;
46
490
  let projectPromise;
47
- let rawProject;
48
491
  let devServer;
49
- let needsSolidHydration = false;
492
+ let hydrationScript = "";
50
493
  let islands = [];
51
494
  const loadProject = async () => {
52
495
  if (project)
53
496
  return project;
54
497
  if (projectPromise)
55
498
  return projectPromise;
56
- projectPromise = (async () => {
57
- const raw = rawProject ?? await compileProject(vite.root);
58
- if (islands.length === 0)
59
- return project = raw;
60
- const ownedServer = devServer ? undefined : await createServer({
61
- root: vite.root,
62
- configFile: vite.configFile ?? false,
63
- server: { middlewareMode: true, hmr: false },
64
- optimizeDeps: { noDiscovery: true, include: [] },
65
- appType: "custom"
66
- });
67
- const server = devServer ?? ownedServer;
68
- const modules = new Map();
499
+ const version = revision;
500
+ const lifetime = new AbortController();
501
+ compilation = lifetime;
502
+ const registry = islands;
503
+ let solidHydrationScript = "";
504
+ const pending = (async () => {
505
+ let owned;
506
+ const createModuleServer = () => nestedServer.run(true, () => createServer(nestedServerConfig(vite)));
507
+ const moduleServer = () => devServer ? Promise.resolve(devServer) : owned ??= createModuleServer();
508
+ // client:none analysis reads client transforms without HMR code, which the dev server would add. It has its
509
+ // own server: client transforms wait for pending requests to settle, and preview renders on the module
510
+ // server are waiting for this analysis.
511
+ let ownedAnalysis;
512
+ const analysisServer = () => ownedAnalysis ??= createModuleServer();
513
+ const analyzed = new Map();
514
+ const analyze = (entry) => {
515
+ let pending = analyzed.get(entry);
516
+ if (!pending) {
517
+ pending = (async () => {
518
+ const server = await analysisServer();
519
+ const { parseAstAsync } = await import("vite");
520
+ const findings = [];
521
+ const seen = new Set();
522
+ const queue = [entry];
523
+ while (queue.length) {
524
+ const url = queue.shift();
525
+ if (seen.has(url))
526
+ continue;
527
+ seen.add(url);
528
+ const result = await server.transformRequest(url);
529
+ if (!result)
530
+ continue;
531
+ const program = await parseAstAsync(result.code);
532
+ findings.push(...findInteractiveConstructs(program, path.join(vite.root, url.split("?")[0])));
533
+ queue.push(...projectImports(program));
534
+ }
535
+ return findings;
536
+ })();
537
+ analyzed.set(entry, pending);
538
+ }
539
+ return pending;
540
+ };
69
541
  try {
70
- return project = await compileIslands(raw, async (name, props, id) => {
71
- const island = islands.find((entry) => entry.name === name);
542
+ const raw = await compileRaw(lifetime.signal, async (file) => createEnvironmentModuleRuntime(await moduleServer(), moduleEnvironment, environmentApiEnabled).loadModule(file));
543
+ if (registry.length === 0) {
544
+ const missing = async (name) => { throw new Error(`Unknown Fuzor component: ${name}`); };
545
+ return await compileIslands(raw, missing, { signal: lifetime.signal });
546
+ }
547
+ const server = await moduleServer();
548
+ const modules = new Map();
549
+ const renderer = async (name, props, id, mode) => {
550
+ const island = registry.find((entry) => entry.name === name);
72
551
  if (!island)
73
552
  throw new Error(`Unknown Fuzor island: ${name}`);
74
- let loaded = modules.get(name);
553
+ const key = name;
554
+ let loaded = modules.get(key);
75
555
  if (!loaded) {
76
- loaded = server.ssrLoadModule(island.file);
77
- modules.set(name, loaded);
556
+ loaded = createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule(island.file);
557
+ modules.set(key, loaded);
78
558
  }
79
559
  const module = await loaded;
560
+ const staticMount = module.mount;
561
+ if (mode === "static") {
562
+ if (staticMount && !staticMount.framework) {
563
+ throw new Error(`${island.file} exports mount(), which client:none never runs. Remove mount() for a build-only component, or use another client: directive.`);
564
+ }
565
+ if (island.file.endsWith(".vue") || staticMount?.framework) {
566
+ const findings = await analyze(island.file);
567
+ if (findings.length)
568
+ throw new Error(`client:none would drop behavior of ${island.file}. It uses:\n${describeFindings(findings, vite.root)}\nUse client:load, client:idle, client:visible or client:interaction instead.`);
569
+ }
570
+ }
80
571
  if (island.file.endsWith(".vue")) {
81
- const [{ createSSRApp }, { renderToString }] = await Promise.all([import("vue"), import("vue/server-renderer")]);
572
+ const load = createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule;
573
+ const { createSSRApp, renderToString } = await load("virtual:fuzor/compiler/vue");
82
574
  return renderToString(createSSRApp(module.default, props));
83
575
  }
84
576
  const mount = module.mount;
85
577
  if (mount?.framework === "react" && mount.component) {
86
- const [{ createElement }, { renderToString }] = await Promise.all([import("react"), import("react-dom/server")]);
87
- return renderToString(createElement(mount.component, props), { identifierPrefix: `fuzor-${id}-` });
578
+ const runtime = runtimes?.scopeOf(island.file)?.key;
579
+ const rendererId = runtime ? `virtual:fuzor/compiler/react@${runtime}` : "virtual:fuzor/compiler/react";
580
+ const load = createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule;
581
+ const { createElement, renderToString } = await load(rendererId);
582
+ if (mode === "static") {
583
+ const { renderToStaticMarkup } = await load(rendererId);
584
+ return renderToStaticMarkup(createElement(mount.component, props));
585
+ }
586
+ const tree = mount.element ? mount.element(props) : createElement(mount.component, props);
587
+ return renderToString(tree, { identifierPrefix: `fuzor-${id}-` });
88
588
  }
89
589
  if (mount?.framework === "solid" && mount.component) {
90
- const [{ createComponent }, { renderToString }] = await Promise.all([import("solid-js"), import("solid-js/web")]);
91
- needsSolidHydration = true;
92
- return renderToString(() => createComponent(mount.component, props), { renderId: id });
590
+ const solidRuntime = runtimes?.scopeOf(island.file)?.key;
591
+ const load = createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule;
592
+ const { createComponent, renderToString, generateHydrationScript } = await load(solidRuntime ? `virtual:fuzor/compiler/solid@${solidRuntime}` : "virtual:fuzor/compiler/solid");
593
+ if (mode === "hydrate")
594
+ solidHydrationScript = generateHydrationScript();
595
+ const html = renderToString(() => createComponent(mount.component, props), { renderId: id });
596
+ // Hydration keys only matter to Solid's client, which a client:none component never loads.
597
+ return mode === "static" ? html.replace(/ data-hk="[^"]*"/g, "") : html;
598
+ }
599
+ // Public adapter contract: any island module may render its preview at build time.
600
+ if (typeof module.render === "function") {
601
+ const html = await module.render(props, { id });
602
+ if (typeof html !== "string")
603
+ throw new Error(`${island.file}: render() must return a string or a promise of one.`);
604
+ return html;
93
605
  }
94
- if (typeof module.render === "function")
95
- return module.render(props);
96
606
  return undefined;
97
- });
607
+ };
608
+ return await compileIslands(raw, renderer, { signal: lifetime.signal });
98
609
  }
99
610
  finally {
100
- await ownedServer?.close();
611
+ if (owned)
612
+ await (await owned).close();
613
+ if (ownedAnalysis) {
614
+ const analysis = await ownedAnalysis;
615
+ // Client transforms can start dependency pre-bundling (Solid's plugin adds entries); closing before it
616
+ // settles leaves esbuild's service referenced and the build process never exits.
617
+ const client = analysis.environments?.client;
618
+ await client?.waitForRequestsIdle?.();
619
+ await client?.depsOptimizer?.scanProcessing;
620
+ await analysis.close();
621
+ }
101
622
  }
102
623
  })();
624
+ const published = pending.then(result => {
625
+ if (version !== revision)
626
+ return loadProject();
627
+ hydrationScript = solidHydrationScript;
628
+ if (options.routeTypes !== false)
629
+ void writeRouteTypes(result).catch(error => vite.logger?.warn(`[fuzor] Could not write .fuzor/routes.d.ts: ${String(error)}`));
630
+ project = pathBase === "/" ? result : { ...result,
631
+ routes: result.routes.map(route => ({ ...route, html: applyBaseToLinks(route.html, pathBase) })),
632
+ ...(result.boundaries ? { boundaries: result.boundaries.map(boundary => ({ ...boundary, html: applyBaseToLinks(boundary.html, pathBase) })) } : {}) };
633
+ return project;
634
+ }, error => {
635
+ if (version !== revision)
636
+ return loadProject();
637
+ throw error;
638
+ });
639
+ projectPromise = published;
103
640
  try {
104
- return await projectPromise;
641
+ return await published;
105
642
  }
106
643
  finally {
107
- projectPromise = undefined;
644
+ if (projectPromise === published)
645
+ projectPromise = undefined;
646
+ if (compilation === lifetime)
647
+ compilation = undefined;
108
648
  }
109
649
  };
110
- const scanIslands = async () => {
111
- const islandDir = path.join(vite.root, "islands");
112
- try {
113
- const entries = await readdir(islandDir, { withFileTypes: true });
114
- islands = entries
115
- .filter((entry) => entry.isFile() && /\.(ts|tsx|js|jsx|vue)$/.test(entry.name))
116
- .map((entry) => ({ name: entry.name.replace(/(?:\.(?:react|solid))?\.(ts|tsx|js|jsx|vue)$/, ""), file: `/islands/${entry.name}` }));
117
- const names = new Set();
118
- for (const island of islands) {
119
- if (names.has(island.name))
120
- throw new Error(`Duplicate Fuzor island name: ${island.name}`);
121
- names.add(island.name);
122
- }
650
+ // Dev servers recompile on every change; unchanged pages come from here.
651
+ const compileCache = new CompileCache();
652
+ let writtenTypes = "";
653
+ const writeRouteTypes = async (compiled) => {
654
+ const file = path.join(vite.root, ".fuzor/routes.d.ts");
655
+ // Import specifiers use .js, which TypeScript maps to the .ts source under Bundler and NodeNext resolution.
656
+ const moduleSpecifier = (source) => {
657
+ const relative = path.relative(path.dirname(file), source).split(path.sep).join("/").replace(/\.ts$/, ".js").replace(/\.mts$/, ".mjs");
658
+ return relative.startsWith(".") ? relative : `./${relative}`;
659
+ };
660
+ const content = routeTypes([
661
+ ...compiled.routes.map(route => ({ pattern: route.pattern ?? route.path, ...(route.paramsSchema ? { paramsModule: moduleSpecifier(route.paramsSchema) } : {}) })),
662
+ ...apiFiles.map(route => route.pattern)
663
+ ]);
664
+ if (content === writtenTypes)
665
+ return;
666
+ if (await readFile(file, "utf8").catch(() => "") !== content) {
667
+ await mkdir(path.dirname(file), { recursive: true });
668
+ await writeFile(file, content, "utf8");
669
+ }
670
+ writtenTypes = content;
671
+ };
672
+ const compileRaw = async (signal, loadModule) => {
673
+ let compiled = await compileProject(vite.root, { ...(options.markdown ? { markdown: options.markdown } : {}), ...(options.redirects ? { redirects: options.redirects } : {}), platform: profile.platform, signal, loadModule, cache: compileCache })
674
+ .catch(async (error) => { throw await withViteLocation(error); });
675
+ const entry = options.entry ?? process.env.FUZOR_ENTRY;
676
+ if (entry) {
677
+ if (!inline || target !== "spa")
678
+ throw new Error("An application entry requires an inline SPA build.");
679
+ const scope = routeKey(entry);
680
+ const rootRoute = compiled.routes.find(route => route.path === scope);
681
+ if (!scope || !rootRoute || rootRoute.policy?.navigation !== "spa")
682
+ throw new Error("Application entry must name a declared SPA boundary.");
683
+ const selected = compiled.routes.filter(route => route.path.startsWith(scope) && route.policy?.navigation === "spa" && route.policy.rendering === "static");
684
+ if (selected.some(route => route.serverData))
685
+ throw new Error("Inline application entries cannot use same-origin server-data endpoints. Use an explicitly hosted backend API in client code, or an HTTP rendering deployment.");
686
+ const rebase = (value) => scope === "/" || !value.startsWith(scope) ? value : "/" + value.slice(scope.length);
687
+ compiled = { ...compiled, routes: selected.map(route => ({ ...route, path: rebase(route.path), html: rewriteNavigationLinks(route.html, rebase), policy: { ...route.policy, spaScope: rebase(route.policy.spaScope ?? scope) } })), boundaries: [], redirects: {} };
688
+ if (!compiled.routes.some(route => route.path === "/"))
689
+ throw new Error("Application entry must have a static root template; request-rendered routes require an HTTP rendering deployment.");
123
690
  }
124
- catch (error) {
125
- if (error.code !== "ENOENT")
126
- throw error;
127
- islands = [];
691
+ const deployment = options.deployment ?? process.env.FUZOR_DEPLOYMENT;
692
+ const requestRoutes = compiled.routes.filter(route => route.policy?.rendering === "request");
693
+ if (deployment && !["static", "github-pages", "node", "cloudflare"].includes(deployment))
694
+ throw new Error("Unknown Fuzor deployment target: " + deployment);
695
+ if ((deployment === "static" || deployment === "github-pages") && (requestRoutes.length || options.serverComponents?.routes.length))
696
+ throw new Error(`Route ${(requestRoutes[0]?.path ?? options.serverComponents.routes[0])} requires request-time server rendering. ${deployment} supports static files only. Pre-render this route, regenerate and republish its files, or choose node/cloudflare rendering. Remote API calls from static SPAs are allowed.`);
697
+ for (const route of requestRoutes)
698
+ if (route.requestPattern && route.policy?.navigation === "spa" && !options.serverComponents?.routes.some(pattern => makeClientRouteMatcher({ [pattern]: "/" })(route.path)))
699
+ throw new Error(`${route.source}: unenumerated request routes inside an SPA require a server-component renderer. Use navigation=document or register serverComponents.`);
700
+ if (options.routeTree) {
701
+ if (target !== "spa" && !profile.mixed)
702
+ throw new Error("routeTree requires a SPA target.");
703
+ makeRouteMatches(options.routeTree);
704
+ const check = (value, seen = new Set()) => {
705
+ if (value === undefined || value === null || typeof value === "string" || typeof value === "boolean" || (typeof value === "number" && Number.isFinite(value)))
706
+ return;
707
+ if (typeof value !== "object" || seen.has(value))
708
+ throw new Error("routeTree handles must be serializable JSON data.");
709
+ if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)
710
+ throw new Error("routeTree handles must be serializable JSON data.");
711
+ seen.add(value);
712
+ for (const child of Object.values(value))
713
+ check(child, seen);
714
+ seen.delete(value);
715
+ };
716
+ check(options.routeTree);
717
+ }
718
+ if (options.clientRoutes && Object.keys(options.clientRoutes).length) {
719
+ if (target !== "spa" || !options.serverComponents && (withServer || apiFiles.length > 0 || serverModuleFiles.length > 0))
720
+ throw new Error("clientRoutes requires a static SPA target.");
721
+ makeClientRouteMatcher(options.clientRoutes);
722
+ for (const target of Object.values(options.clientRoutes)) {
723
+ const route = compiled.routes.find(route => route.path === routeKey(target));
724
+ if (!route)
725
+ throw new Error(`Client route template ${target} is not compiled.`);
726
+ if (route.serverData)
727
+ throw new Error("Client route templates cannot have server data.");
728
+ }
128
729
  }
730
+ for (const warning of compiled.warnings ?? [])
731
+ vite.logger.warn(`[fuzor] ${warning}`);
732
+ const shadowed = apiFiles.length ? compiled.routes.find(route => route.path === "/api/" || route.path.startsWith("/api/")) : undefined;
733
+ if (shadowed)
734
+ throw new Error(`${path.relative(vite.root, shadowed.source)} is below /api/, which belongs to the api/ folder. Move the page.`);
735
+ const extracted = extractPageScripts(compiled, vite.root);
736
+ pageScripts = extracted.scripts;
737
+ scriptRoutes = extracted.routes;
738
+ return extracted.project;
739
+ };
740
+ const scanIslands = async () => {
741
+ return Effect.runPromise(scanIslandModulesEffect(vite.root, Object.keys(options.runtimes ?? {})));
129
742
  };
130
743
  const refresh = async (server) => {
744
+ const version = ++revision;
745
+ viewBuildId = randomUUID();
746
+ referencesPromise = undefined;
747
+ compilation?.abort();
131
748
  project = undefined;
132
- rawProject = undefined;
133
749
  projectPromise = undefined;
134
- needsSolidHydration = false;
135
- await scanIslands();
750
+ hydrationScript = "";
751
+ const nextApi = findApiRoutes(vite.root);
752
+ const nextModules = (options.entry ?? process.env.FUZOR_ENTRY) && inline ? [] : [...findServerModules(vite.root), ...nextApi.map(route => route.relative)];
753
+ const nextProfile = resolveFuzorProfile(options, process.env, nextModules);
754
+ apiFiles = nextApi;
755
+ serverModuleFiles = nextModules;
756
+ profile = nextProfile;
757
+ withServer = profile.server;
758
+ const nextIslands = await scanIslands();
759
+ if (version !== revision)
760
+ return;
761
+ islands = nextIslands;
136
762
  await loadProject();
137
- const module = server.moduleGraph.getModuleById(resolvedVirtualId);
138
- if (module)
139
- server.moduleGraph.invalidateModule(module);
763
+ if (version !== revision)
764
+ return;
765
+ invalidateEnvironmentModule(server, resolvedVirtualId, environmentNames.client, environmentApiEnabled);
766
+ environmentState.set(environmentNames.server, { revision, ...(project ? { project } : {}) });
140
767
  server.ws.send({ type: "full-reload" });
141
768
  };
142
769
  return {
143
770
  name: "fuzor",
144
771
  enforce: "pre",
145
- config() {
146
- if (withServer)
147
- return { build: { outDir: serverOutDir } };
148
- if (target === "spa" && inline)
149
- return {
150
- build: {
151
- cssCodeSplit: false,
152
- assetsInlineLimit: Number.MAX_SAFE_INTEGER,
153
- rollupOptions: { output: { inlineDynamicImports: true } }
154
- }
155
- };
772
+ api: {
773
+ profile: () => profile,
774
+ project: () => loadProject(),
775
+ apiRoutes: () => apiFiles.map(route => ({ pattern: route.pattern, source: route.relative })),
776
+ environments: () => ({ ...environmentNames }),
777
+ environmentApi: () => environmentCapability
778
+ },
779
+ async config(config) {
780
+ const projectRoot = path.resolve(config.root ?? process.cwd());
781
+ runtimes = createRuntimes(projectRoot, options.runtimes);
782
+ // Dependency pre-bundling resolves imports inside aliased packages with its own bundler.
783
+ const viteModule = runtimes.enabled ? await import("vite") : {};
784
+ const runtimeOptimizer = runtimes.enabled ? (() => {
785
+ const active = runtimes;
786
+ const rootFile = path.join(projectRoot, "package.json");
787
+ // Vite 8 bundles dependencies with Rolldown and exports its version; earlier majors use esbuild.
788
+ if ("rolldownVersion" in viteModule) {
789
+ return { rolldownOptions: { plugins: [{ name: "fuzor:runtimes", async resolveId(source, importer) {
790
+ const runtime = importer ? active.packageScope(importer) : undefined;
791
+ const mapped = runtime && active.mapSpecifier(runtime, source);
792
+ return mapped ? this.resolve(mapped, rootFile, { skipSelf: true }) : null;
793
+ } }] } };
794
+ }
795
+ return { esbuildOptions: { plugins: [{ name: "fuzor:runtimes", setup(build) {
796
+ build.onResolve({ filter: /^[\w@]/ }, async (args) => {
797
+ const runtime = args.importer ? active.packageScope(args.importer) : undefined;
798
+ const mapped = runtime && active.mapSpecifier(runtime, args.path);
799
+ if (!mapped)
800
+ return undefined;
801
+ const result = await build.resolve(mapped, { kind: args.kind, resolveDir: projectRoot });
802
+ return result.errors.length ? { errors: result.errors } : { path: result.path, external: result.external, namespace: result.namespace };
803
+ });
804
+ } }] } };
805
+ })() : {};
806
+ if (nested)
807
+ return { resolve: { dedupe: ["react", "react-dom", "solid-js", "vue"] }, ...(runtimes.enabled ? { optimizeDeps: runtimeOptimizer } : {}) };
808
+ apiFiles = findApiRoutes(path.resolve(config.root ?? process.cwd()));
809
+ serverModuleFiles = (options.entry ?? process.env.FUZOR_ENTRY) && inline ? [] : [...findServerModules(path.resolve(config.root ?? process.cwd())), ...apiFiles.map(route => route.relative)];
810
+ profile = resolveFuzorProfile(options, process.env, serverModuleFiles);
811
+ ({ target, inline } = profile);
812
+ withServer = profile.server;
813
+ if (options.clientRoutes && Object.keys(options.clientRoutes).length && (target !== "spa" || withServer && !options.serverComponents))
814
+ throw new Error("clientRoutes requires a static SPA target.");
815
+ const packageJson = await readFile(path.join(path.resolve(config.root ?? process.cwd()), "package.json"), "utf8").then(text => JSON.parse(text), () => ({}));
816
+ const dependencies = { ...packageJson.dependencies, ...packageJson.devDependencies };
817
+ const include = ["Cause", "Context", "Deferred", "Effect", "Exit", "Fiber", "Layer", "Schema", "Scope", "reactivity/Atom", "reactivity/AtomRegistry"].map(module => `fuzor > effect/${module}`);
818
+ if (dependencies.react && dependencies["react-dom"])
819
+ include.push("react", "react-dom/client", "react/jsx-runtime", "react/jsx-dev-runtime");
820
+ if (dependencies.vue)
821
+ include.push("vue");
822
+ return {
823
+ resolve: { dedupe: ["react", "react-dom", "solid-js", "vue"] },
824
+ optimizeDeps: { include, ...runtimeOptimizer },
825
+ // Vite 6.4 accepts named environments in the config hook. This is
826
+ // emitted only for explicit opt-in; Vite 6/7 legacy users are untouched.
827
+ ...(options.experimental?.environments ? {
828
+ environments: Object.fromEntries(Object.values(environmentNames).filter(name => name !== "client").map(name => [name, { consumer: "server" }]))
829
+ } : {}),
830
+ build: {
831
+ ...(config.build?.outDir === undefined ? { outDir: process.env.FUZOR_STAGE_DIR ? path.join(process.env.FUZOR_STAGE_DIR, profile.outDir) : profile.outDir } : {}),
832
+ ...(target === "spa" && inline ? { cssCodeSplit: false, modulePreload: false, assetsInlineLimit: Number.MAX_SAFE_INTEGER } : {})
833
+ }
834
+ };
156
835
  },
157
836
  async configResolved(config) {
158
837
  vite = config;
159
- rawProject = await compileProject(config.root);
160
- await scanIslands();
838
+ environmentCapability = detectViteEnvironmentApi({ config });
839
+ pathBase = normalizeBase(config.base);
840
+ if (nested)
841
+ return;
842
+ islands = await scanIslands();
843
+ checkRendererVersions(config.root, islands, options.runtimes);
844
+ if (runtimes?.enabled) {
845
+ const vueRuntime = islands.find(island => island.file.endsWith(".vue") && runtimes.scopeOf(island.file));
846
+ if (vueRuntime)
847
+ throw new Error(`${vueRuntime.file}: runtimes support JSX islands only. Vue's compiler adds its own imports of vue, which Fuzor cannot redirect.`);
848
+ }
849
+ },
850
+ async resolveId(id, importer, resolveOptions) {
851
+ if (!resolveOptions.ssr)
852
+ assertBrowserViewImport(id, importer);
853
+ if (id === "fuzor/server-components/server" && !resolveOptions.ssr) {
854
+ throw new Error("The server-component evaluator is server-only. Import browser runtime and protocol separately.");
855
+ }
856
+ if (id.startsWith("virtual:fuzor/route-client/"))
857
+ return `\0${id}`;
858
+ if (id.startsWith("virtual:fuzor/page-script/"))
859
+ return `\0${id}`;
860
+ if (id.startsWith("virtual:fuzor/native-handler/"))
861
+ return `\0${id}`;
862
+ if (importer?.startsWith("\0virtual:fuzor/native-handler/") && id.startsWith(".")) {
863
+ const handler = [...nativeHandlers.values()].find(handler => importer === `\0virtual:fuzor/native-handler/${handler.id}.js`);
864
+ if (handler)
865
+ return this.resolve(path.resolve(path.dirname(handler.source), id), undefined, { skipSelf: true });
866
+ }
867
+ if (importer?.startsWith("\0virtual:fuzor/page-script/")) {
868
+ const script = pageScripts.find(script => `\0${pageScriptId(script)}` === importer);
869
+ if (script)
870
+ return this.resolve(id, script.source, { ...resolveOptions, skipSelf: true });
871
+ }
872
+ if (id.endsWith(".fragment.html")) {
873
+ const file = await this.resolve(id, importer, { ...resolveOptions, skipSelf: true });
874
+ if (file)
875
+ return file.id.startsWith("\0fuzor:fragment:") ? file.id : `\0fuzor:fragment:${file.id}.js`;
876
+ }
877
+ if (id.startsWith("virtual:fuzor/closure/"))
878
+ return `\0fuzor:closure:${id.slice("virtual:fuzor/closure/".length)}.ts`;
879
+ if (id === "virtual:fuzor/views" || id === virtualId || Object.hasOwn(rendererModules, id))
880
+ return `\0${id}`;
881
+ if (id === "fuzor/ui" || id.startsWith("fuzor/ui/")) {
882
+ const projectImporter = importer && !importer.startsWith("\0") ? importer : path.join(vite.root, "package.json");
883
+ const resolved = await this.resolve(id, projectImporter, { ...resolveOptions, skipSelf: true });
884
+ if (resolved)
885
+ return resolved;
886
+ // Virtual docs imports can resolve against Fuzor itself when the host
887
+ // does not expose a workspace link at the project root.
888
+ const fallback = id === "fuzor/ui" ? `fuzor/ui/${resolveOptions.ssr ? "server" : "client"}` : id;
889
+ const local = await this.resolve(fallback, fileURLToPath(import.meta.url), { ...resolveOptions, skipSelf: true });
890
+ if (local)
891
+ return local;
892
+ try {
893
+ return fileURLToPath(import.meta.resolve(fallback));
894
+ }
895
+ catch { }
896
+ }
897
+ if (!runtimes?.enabled)
898
+ return undefined;
899
+ // `virtual:fuzor/compiler/react@react18`: a build-time renderer for one runtime.
900
+ const renderer = /^(virtual:fuzor\/compiler\/(?:react|solid))@([a-z0-9]+)$/.exec(id);
901
+ if (renderer && Object.hasOwn(rendererModules, renderer[1]) && runtimes.keys().includes(renderer[2])) {
902
+ const resolved = `\0${id}`;
903
+ runtimeModules.set(resolved, () => runtimes.renderer(renderer[2], rendererModules[renderer[1]]));
904
+ return resolved;
905
+ }
906
+ const adapter = runtimes.adapter(id);
907
+ if (adapter) {
908
+ runtimeModules.set(adapter.id, adapter.load);
909
+ return adapter.id;
910
+ }
911
+ const scope = runtimes.scopeOf(importer);
912
+ if (!scope || !importer)
913
+ return undefined;
914
+ const insidePackage = runtimes.packageScope(importer.split("?")[0]);
915
+ if (insidePackage) {
916
+ // react-dom-18 importing react must get react-18, which is installed at the project root.
917
+ const mapped = runtimes.mapSpecifier(insidePackage, id);
918
+ return mapped ? this.resolve(mapped, path.join(vite?.root ?? process.cwd(), "package.json"), { ...resolveOptions, skipSelf: true }) : undefined;
919
+ }
920
+ if (!id.startsWith(".") && !id.startsWith("/"))
921
+ return undefined;
922
+ const resolved = await this.resolve(id, importer, { ...resolveOptions, skipSelf: true });
923
+ if (resolved && !resolved.external)
924
+ runtimes.assign(resolved.id.split("?")[0], scope);
925
+ return resolved;
161
926
  },
162
- resolveId(id) {
163
- return id === virtualId ? resolvedVirtualId : undefined;
927
+ transform: {
928
+ order: "pre",
929
+ handler(code, id) {
930
+ if (!/\.[cm]?[jt]sx?$/.test(id.split("?")[0]) || id.includes("/node_modules/"))
931
+ return undefined;
932
+ const workflow = compileWorkflows(code, id);
933
+ if (workflow)
934
+ return workflow;
935
+ if (!runtimes?.enabled || id.startsWith(runtimes.resolvedPrefix))
936
+ return undefined;
937
+ if (!/\.[cm]?[jt]sx?$/.test(id.split("?")[0]))
938
+ return undefined;
939
+ const scope = runtimes.scopeOf(id);
940
+ if (!scope || runtimes.packageScope(id.split("?")[0]))
941
+ return undefined;
942
+ return runtimes.transform(scope, code, id);
943
+ }
164
944
  },
165
- load(id) {
945
+ async load(id, loadOptions) {
946
+ if (id.startsWith("\0virtual:fuzor/route-client/")) {
947
+ await loadProject();
948
+ const route = scriptRoutes.find(route => `\0${routeScriptId(route)}` === id);
949
+ if (!route)
950
+ throw new Error("Unknown Fuzor route client entry");
951
+ return `export const bindings = [${route.bindings.map(binding => `{ ...${JSON.stringify(binding)}, load: () => import(${JSON.stringify(pageScriptId(pageScripts.find(script => script.id === binding.id)))}) }`).join(",")}];`;
952
+ }
953
+ if (id.startsWith("\0virtual:fuzor/page-script/")) {
954
+ await loadProject();
955
+ const script = pageScripts.find(script => `\0${pageScriptId(script)}` === id);
956
+ if (!script)
957
+ throw new Error("Unknown Fuzor page script");
958
+ this.addWatchFile(script.source);
959
+ const source = script.code ?? await readFile(script.source, "utf8");
960
+ const native = compileNativeScript(source, script);
961
+ if (native) {
962
+ for (const handler of native.handlers)
963
+ nativeHandlers.set(handler.id, handler);
964
+ return (await import("vite")).transformWithEsbuild(native.code, script.source, { loader: script.language, target: "es2022", sourcefile: script.source });
965
+ }
966
+ const compiled = compilePageScript(source, script);
967
+ return (await import("vite")).transformWithEsbuild(compiled.code, script.source, { loader: script.language, target: "es2022", sourcemap: true, sourcefile: script.source }, compiled.map);
968
+ }
969
+ if (id.startsWith("\0virtual:fuzor/native-handler/")) {
970
+ const handler = [...nativeHandlers.values()].find(handler => id === `\0virtual:fuzor/native-handler/${handler.id}.js`);
971
+ if (!handler)
972
+ throw new Error("Unknown native handler");
973
+ return (await import("vite")).transformWithEsbuild(handler.code, handler.source, { loader: handler.language, target: "es2022" });
974
+ }
975
+ if (id.startsWith("\0fuzor:closure:")) {
976
+ const refs = await references();
977
+ const closure = refs.closures.find(ref => id === `\0fuzor:closure:${ref.id}.ts`);
978
+ if (!closure)
979
+ throw new Error("Unknown resumable closure reference");
980
+ return (await import("vite")).transformWithEsbuild(closure.code, id, { loader: "ts", target: "es2022" }).then(result => result.code);
981
+ }
982
+ if (options.serverComponents?.references) {
983
+ const refs = await references();
984
+ if (id === "\0virtual:fuzor/views") {
985
+ if (loadOptions?.ssr)
986
+ return `export const manifest=${JSON.stringify({ buildId: viewBuildId, templates: refs.templates })}; export const components=${JSON.stringify(refs.clients.map(ref => ref.id))}; export const handlers=${JSON.stringify([...refs.handlers.map(ref => ref.id), ...refs.closures.map(ref => ref.id)])};`;
987
+ return browserReferencesCode(refs, viewBuildId, file => "/" + file);
988
+ }
989
+ if (loadOptions?.ssr) {
990
+ const stub = referenceStub(id.split("?")[0], refs);
991
+ if (stub)
992
+ return stub;
993
+ }
994
+ }
995
+ if (id.startsWith("\0fuzor:fragment:")) {
996
+ const file = id.slice("\0fuzor:fragment:".length, -3);
997
+ this.addWatchFile(file);
998
+ return readFile(file, "utf8").then(html => `export default ${JSON.stringify(compileFragment(html))};`);
999
+ }
1000
+ if (Object.hasOwn(rendererModules, id.slice(1)))
1001
+ return rendererModules[id.slice(1)];
1002
+ const runtimeModule = runtimeModules.get(id);
1003
+ if (runtimeModule)
1004
+ return runtimeModule();
1005
+ if (!loadOptions?.ssr && !nested && vite) {
1006
+ const file = id.split("?")[0];
1007
+ const relative = path.relative(vite.root, file).split(path.sep).join("/");
1008
+ if (options.serverComponents && path.resolve(vite.root, options.serverComponents.server) === file || serverModuleFiles.includes(relative) || relative.startsWith("api/") || /\.server\.[cm]?[jt]sx?$/.test(relative)) {
1009
+ throw new Error(`${relative} is server-only and cannot be imported by browser code. Read its data with <fuzor-data> or routeData() instead.`);
1010
+ }
1011
+ }
166
1012
  if (id !== resolvedVirtualId)
167
1013
  return undefined;
1014
+ await loadProject();
1015
+ const mixedClient = profile.mixed && project?.routes.some(route => route.policy?.navigation === "spa");
1016
+ const scriptRegistry = scriptRoutes.map(route => `${JSON.stringify(route.path)}: () => import(${JSON.stringify(routeScriptId(route))}).catch(reloadOnStaleDeployment)`).join(",\n");
168
1017
  const registry = islands.map((island) => {
169
1018
  const load = island.file.endsWith(".vue")
170
- ? `Promise.all([import(${JSON.stringify(island.file)}), import("fuzor/islands/vue")]).then(([component, adapter]) => adapter.vueIsland(component.default))`
171
- : `import(${JSON.stringify(island.file)})`;
1019
+ ? `Promise.all([import(${JSON.stringify(island.file)}), import("fuzor/islands/vue")]).then(([component, adapter]) => adapter.vueIsland(component.default)).catch(reloadOnStaleDeployment)`
1020
+ : `import(${JSON.stringify(island.file)}).catch(reloadOnStaleDeployment)`;
172
1021
  return `${JSON.stringify(island.name)}: () => ${load}`;
173
1022
  }).join(",\n");
174
- return `import { ${target === "spa" ? "createRouter" : "mountIslands"} } from "${target === "spa" ? "fuzor/runtime" : "fuzor/runtime/islands"}";
1023
+ const withData = target === "mpa" && !!project?.routes.some(route => route.serverData);
1024
+ const hasDocs = (project?.routes ?? []).some(route => route.path === "/docs/" || route.path.startsWith("/docs/"));
1025
+ const routerModule = profile.electron || options.navigation === "embedded" ? "fuzor/runtime/router/embedded" : options.navigation === "navigation-api" ? "fuzor/runtime/router/navigation-api" : "fuzor/runtime";
1026
+ const imports = [
1027
+ (target === "spa" || mixedClient)
1028
+ ? `import { createRouter } from "${routerModule}"; import { reloadOnStaleDeployment } from "fuzor/runtime/islands";`
1029
+ : 'import { mountIslands, islandErrorHandler, reloadOnStaleDeployment } from "fuzor/runtime/islands";',
1030
+ ...(target === "mpa" ? ['import { mountPageScripts } from "fuzor/runtime/page-scripts"; import { stripBase } from "fuzor/runtime";'] : []),
1031
+ ...(options.serverComponents ? [options.serverComponents.references ? 'import generatedViewOptions from "virtual:fuzor/views";' : "", options.serverComponents.client ? `import suppliedViewOptions from ${JSON.stringify("/" + options.serverComponents.client)};` : "", `const viewOptions = { ${options.serverComponents.references ? "...generatedViewOptions" : ""}${options.serverComponents.references && options.serverComponents.client ? "," : ""}${options.serverComponents.client ? "...suppliedViewOptions" : ""} };`, (target === "spa" || mixedClient) ? 'import { makeClientRouteMatcher } from "fuzor/runtime"; import { serverViewRoutes } from "fuzor/server-components/navigation"; import { createViewRenderer } from "fuzor/server-components/browser";' : 'import { createViewRenderer } from "fuzor/server-components/browser";'] : []),
1032
+ ...(mixedClient ? ['import { mountIslands, islandErrorHandler } from "fuzor/runtime/islands";'] : []),
1033
+ ...(withData ? ['import { loadRouteData } from "fuzor/runtime/data";'] : []),
1034
+ ...(hasDocs ? ['import { mountDocsUi } from "fuzor/runtime/docs-ui";'] : [])
1035
+ ];
1036
+ const docsInit = hasDocs ? `let stopDocsUi;
1037
+ let docsDisposed = false;
1038
+ const hideDocs = event => { if (!event.persisted) disposeDocs(); };
1039
+ const disposeDocs = () => {
1040
+ if (docsDisposed) return;
1041
+ docsDisposed = true;
1042
+ window.removeEventListener("pagehide", hideDocs);
1043
+ stopDocsUi?.();
1044
+ };
1045
+ void mountDocsUi({ document, base: import.meta.env.BASE_URL }).then(stop => {
1046
+ stopDocsUi = stop;
1047
+ if (docsDisposed) stop();
1048
+ }, error => console.error(error));
1049
+ window.addEventListener("pagehide", hideDocs);
1050
+ if (import.meta.hot) import.meta.hot.dispose(disposeDocs);
1051
+ ` : "";
1052
+ const effectiveViewOptions = `...viewOptions, manifest: { ...viewOptions.manifest, buildId: ${JSON.stringify(viewBuildId)} }`;
1053
+ const spaStart = `export const router = (${mixedClient ? 'outlet.getAttribute("data-fuzor-navigation") === "spa" && ' : ""}!outlet.hasAttribute("data-fuzor-not-found") && !outlet.hasAttribute("data-fuzor-error")) ? createRouter(outlet, { islands, scripts, base: import.meta.env.BASE_URL${options.serverComponents ? `, renderer: serverViewRoutes({ ${effectiveViewOptions}, routes: ${JSON.stringify(options.serverComponents.routes)}, acceptsRoute: path => !${mixedClient} || [...document.querySelectorAll("template[data-fuzor-route]")].some(t => t.getAttribute("data-fuzor-route") === path || t.hasAttribute("data-fuzor-request-pattern") && makeClientRouteMatcher({[t.getAttribute("data-fuzor-request-pattern")]: "/"})(path)), base: import.meta.env.BASE_URL })` : ""}${options.clientRoutes ? `, clientRoutes: ${JSON.stringify(options.clientRoutes)}` : ""}${options.routeTree ? `, routeTree: ${JSON.stringify(options.routeTree)}` : ""}${options.viewTransitions ? ", viewTransitions: true" : ""}${options.prefetch === "intent" ? ', prefetch: "intent"' : ""} }) : undefined;
1054
+ export const ready = router ? router.start() : Promise.resolve(undefined);
1055
+ void ready.catch(error => console.error(error));
1056
+ if (import.meta.hot) import.meta.hot.dispose(() => { void router?.dispose(); });`;
1057
+ const mpaStart = `${withData ? `if (outlet.hasAttribute("data-fuzor-data") && !outlet.hasAttribute("data-fuzor-data-ready")) void loadRouteData(outlet).catch(error => { if (error?.name !== "AbortError") console.error(error); });
1058
+ ` : ""}if (!/^https?:$/.test(location.protocol)) console.error("Fuzor MPA builds need an HTTP(S) server: their root-relative links and assets do not resolve over " + location.protocol + " URLs. Use an inline SPA build (fuzor build --target spa --inline) for embedded apps.");
1059
+ const lifetime = new AbortController();
1060
+ let cleanup;
1061
+ const dispose = () => { lifetime.abort(); void cleanup?.(); };
1062
+ ${options.serverComponents ? `const viewRenderer = document.querySelector("script[data-fuzor-snapshot]") ? createViewRenderer(outlet, { ${effectiveViewOptions} }) : undefined;
1063
+ const mountComponents = viewRenderer ? viewRenderer.resume().then(() => () => viewRenderer.dispose()) : mountIslands(outlet, islands, islandErrorHandler, { signal: lifetime.signal });` : `const mountComponents = mountIslands(outlet, islands, islandErrorHandler, { signal: lifetime.signal });`}
1064
+ ${options.serverComponents ? "const viewRendererActive = !!viewRenderer;" : "const viewRendererActive = false;"}
1065
+ const pathname = stripBase(location.pathname, import.meta.env.BASE_URL) ?? location.pathname;
1066
+ const routePath = pathname.endsWith("/") ? pathname : pathname + "/";
1067
+ const scriptRoute = Object.hasOwn(scripts, routePath) ? routePath : outlet.getAttribute("data-fuzor-pattern") ?? "";
1068
+ const mount = (async () => { const stopComponents = await mountComponents; try { const stopScripts = await mountPageScripts(outlet, viewRendererActive ? {} : scripts, { signal: lifetime.signal, route: scriptRoute }); return async () => { await stopScripts(); await stopComponents(); }; } catch (error) { await stopComponents(); throw error; } })();
1069
+ void mount.then(stop => {
1070
+ cleanup = stop;
1071
+ if (lifetime.signal.aborted) void stop();
1072
+ }, error => { if (!lifetime.signal.aborted) console.error(error); });
1073
+ window.addEventListener("pagehide", event => { if (!event.persisted) dispose(); });
1074
+ if (import.meta.hot) import.meta.hot.dispose(dispose);`;
1075
+ return `${imports.join("\n")}
175
1076
  const islands = { ${registry} };
1077
+ const scripts = { ${scriptRegistry} };
176
1078
  const outlet = document.querySelector("fuzor-router");
177
1079
  if (!outlet) throw new Error("Fuzor outlet is missing");
178
- ${target === "spa"
179
- ? "if (!outlet.hasAttribute(\"data-fuzor-not-found\")) void createRouter(outlet, { islands }).start();"
180
- : "void mountIslands(outlet, islands);"}`;
1080
+ window.addEventListener("vite:preloadError", event => { event.preventDefault(); void reloadOnStaleDeployment(event.payload).catch(error => console.error(error)); });
1081
+ ${docsInit}${mixedClient ? spaStart + "\nif (!router) {\n" + mpaStart + "\n}" : target === "spa" ? spaStart : mpaStart}`;
181
1082
  },
182
1083
  transformIndexHtml: {
183
1084
  order: "pre",
184
1085
  async handler(raw, context) {
1086
+ if (nested)
1087
+ return raw;
185
1088
  const compiled = await loadProject();
186
- const pathname = target === "spa" ? "/" : new URL(context.path, "http://fuzor.local").pathname;
187
- const currentPath = compiled.routes.some((route) => route.path === (pathname === "/" ? "/" : `${pathname.replace(/\/+$/, "")}/`)) ? pathname : "/";
188
- let html = replaceOutlet(raw, outletFor(compiled, target, currentPath));
189
- if (needsSolidHydration) {
190
- const { generateHydrationScript } = await import("solid-js/web");
191
- html = html.replace("</head>", `${generateHydrationScript()}</head>`);
1089
+ const requested = new URL(context.path, "http://fuzor.local").pathname;
1090
+ const pathname = stripBase(requested, pathBase) ?? requested;
1091
+ const currentPath = findRoute(compiled, pathname) ? pathname : "/";
1092
+ parseRoutePolicy(raw, path.join(vite.root, "index.html"), false);
1093
+ const shell = compilePlatformBlocks(raw, profile.platform, path.join(vite.root, "index.html"));
1094
+ shellHead = readDocumentHead(shell);
1095
+ let html = applyDocumentMetadata(replaceOutlet(shell, outletFor(compiled, target, currentPath, fallbacks(), profile.mixed)), pageHead(shellHead, findRoute(compiled, currentPath)?.metadata ?? {}));
1096
+ if (inline && target === "spa") {
1097
+ const initial = findRoute(compiled, currentPath);
1098
+ const script = await inlineInitialRouteScript({ base: pathBase, alwaysHash: profile.electron || options.navigation === "embedded", ...(options.clientRoutes ? { clientRoutes: options.clientRoutes } : {}) });
1099
+ // A route never becomes visible until the synchronous selector chooses it.
1100
+ html = html.replace(/<fuzor-router\b[^>]*>[\s\S]*?<\/fuzor-router>/, "<fuzor-router></fuzor-router>");
1101
+ const fallback = `<noscript>${initial?.html ?? ""}<p>JavaScript is required to navigate this single-file app.</p></noscript>`;
1102
+ html = html.replace(outletEnd, () => `${script}${fallback}${outletEnd}`);
192
1103
  }
1104
+ if (options.generator !== false)
1105
+ html = applyGeneratorMetadata(html);
1106
+ if (hydrationScript)
1107
+ html = html.replace("</head>", `${hydrationScript}</head>`);
1108
+ if (vite.command === "serve")
1109
+ html = withStaticModuleImports(html);
193
1110
  html = html.replace("</head>", `<script type="module">import "${virtualId}";</script></head>`);
194
1111
  return html;
195
1112
  }
196
1113
  },
197
1114
  configureServer(server) {
1115
+ if (nested)
1116
+ return;
198
1117
  devServer = server;
199
- if (withServer || target === "mpa") {
200
- server.middlewares.use(async (request, response, next) => {
201
- const pathname = new URL(request.url ?? "/", "http://fuzor.local").pathname;
202
- if (withServer && !pathname.startsWith("/@") && !pathname.startsWith("/__") && !pathname.includes(".")) {
203
- try {
1118
+ releaseRuntimeHooks();
1119
+ releaseRuntimeHooks = runtimes?.registerNodeHooks() ?? (() => { });
1120
+ // Install before profile detection changes so adding the first server module works in SPA too.
1121
+ server.middlewares.use(async (request, response, next) => {
1122
+ const requested = new URL(request.url ?? "/", "http://fuzor.local").pathname;
1123
+ const pathname = stripBase(requested, pathBase);
1124
+ if (pathname === undefined)
1125
+ return next();
1126
+ if (pathname === "/search-index.json" && options.searchIndex) {
1127
+ try {
1128
+ response.setHeader("content-type", "application/json; charset=utf-8");
1129
+ response.end(searchIndex(await loadProject(), options.searchIndex));
1130
+ }
1131
+ catch (error) {
1132
+ next(error);
1133
+ }
1134
+ return;
1135
+ }
1136
+ if (!withServer && target === "spa")
1137
+ return next();
1138
+ const dataRequest = pathname.startsWith(`${serverDataPrefix}/`);
1139
+ const apiRequest = apiFiles.length > 0 && (pathname === "/api" || pathname.startsWith("/api/"));
1140
+ // Explicit Vite proxies own their upstream APIs; server views must not turn them into HTML routes.
1141
+ if (!apiRequest && Object.keys(server.config.server.proxy ?? {}).some(prefix => prefix.startsWith("^") ? new RegExp(prefix).test(requested) : requested === prefix || requested.startsWith(prefix + "/")))
1142
+ return next();
1143
+ if (withServer && (dataRequest || apiRequest || !pathname.startsWith("/@") && !pathname.startsWith("/__") && !pathname.includes("."))) {
1144
+ const controller = new AbortController();
1145
+ const abort = () => { if (!response.writableFinished)
1146
+ controller.abort(); };
1147
+ request.once("aborted", abort);
1148
+ response.once("close", abort);
1149
+ try {
1150
+ const onError = (error) => server.config.logger.error(`[fuzor] ${error instanceof Error ? error.stack ?? error.message : String(error)}`);
1151
+ const url = new URL(request.url ?? "/", `http://${request.headers.host ?? "fuzor.local"}`);
1152
+ let result;
1153
+ if (apiRequest) {
1154
+ // Rescanned per request so new endpoint files work without restarting.
1155
+ const api = await loadApiModules(findApiRoutes(vite.root), file => createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule(file));
1156
+ result = await createServerHandler({ documents: {}, notFoundDocument: "", ...(pathBase === "/" ? {} : { base: pathBase }) }, { api, onError })(toWebRequest(request, { url, signal: controller.signal }));
1157
+ }
1158
+ else {
204
1159
  const raw = await readFile(path.join(vite.root, "index.html"), "utf8");
205
1160
  const template = await server.transformIndexHtml("/", raw);
206
1161
  const compiled = await loadProject();
207
- const notFoundDocument = replaceOutlet(template, '<fuzor-router data-fuzor-not-found><h1>Not found</h1></fuzor-router>');
208
- const manifest = target === "spa"
209
- ? { document: template, routes: Object.fromEntries(compiled.routes.map((route) => [route.path, true])), notFoundDocument }
210
- : { documents: Object.fromEntries(compiled.routes.map((route) => [route.path, replaceOutlet(template, `<fuzor-router>${route.html}</fuzor-router>`)])), notFoundDocument };
211
- const result = await createServerHandler(manifest)(new Request(new URL(request.url ?? "/", "http://fuzor.local"), { method: request.method ?? "GET" }));
212
- response.writeHead(result.status, Object.fromEntries(result.headers));
213
- response.end(Buffer.from(await result.arrayBuffer()));
214
- }
215
- catch (error) {
216
- next(error);
1162
+ const manifest = serverManifest(compiled, target, template, pathBase, fallbacks(), withStaticModuleImports, options.clientRoutes, `/${vite.build.assetsDir}/`, profile.mixed);
1163
+ const data = dataRequest || compiled.routes.some(route => route.policy?.rendering === "request") ? await loadRouteDataModules(compiled, file => createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule(file), vite.root) : undefined;
1164
+ const views = options.serverComponents ? await generatedViews((await createEnvironmentModuleRuntime(server, moduleEnvironment, environmentApiEnabled).loadModule("/" + options.serverComponents.server)).default) : undefined;
1165
+ if (views && JSON.stringify(Object.keys(views.routes).sort()) !== JSON.stringify([...options.serverComponents.routes].sort()))
1166
+ throw new Error("Server view routes must match serverComponents.routes.");
1167
+ result = await createServerHandler(manifest, { ...(data ? { data } : {}), ...(views ? { views: { ...views, manifest: { ...views.manifest, buildId: viewBuildId }, documentPatterns: manifest.requestPatterns ?? {}, document: serverViewDocument(template), documents: Object.fromEntries(Object.entries("documents" in manifest ? manifest.documents : manifest.routeDocuments ?? {}).map(([route, html]) => [route, serverViewDocument(html)])) } } : {}), onError })(toWebRequest(request, { url, signal: controller.signal }));
217
1168
  }
218
- return;
219
- }
220
- if (request.method !== "GET")
221
- return next();
222
- const normalized = pathname === "/" ? "/" : `${pathname.replace(/\/+$/, "")}/`;
223
- if (normalized === "/" || !(await loadProject()).routes.some((route) => route.path === normalized))
224
- return next();
225
- try {
226
- const raw = await readFile(path.join(vite.root, "index.html"), "utf8");
227
- const html = await server.transformIndexHtml(pathname, raw);
228
- response.setHeader("content-type", "text/html; charset=utf-8");
229
- response.end(html);
1169
+ await writeWebResponse(response, result, { method: request.method ?? "GET", signal: controller.signal });
230
1170
  }
231
1171
  catch (error) {
232
- next(error);
1172
+ if (!controller.signal.aborted) {
1173
+ if (response.headersSent) {
1174
+ server.config.logger.error(String(error));
1175
+ response.destroy();
1176
+ }
1177
+ else
1178
+ next(error);
1179
+ }
233
1180
  }
234
- });
235
- }
1181
+ finally {
1182
+ request.removeListener("aborted", abort);
1183
+ response.removeListener("close", abort);
1184
+ }
1185
+ return;
1186
+ }
1187
+ if (request.method !== "GET")
1188
+ return next();
1189
+ const normalized = routeKey(pathname);
1190
+ const redirect = normalized === undefined ? undefined : (await loadProject()).redirects?.[normalized];
1191
+ if (redirect !== undefined) {
1192
+ response.writeHead(308, { location: /^https?:\/\//i.test(redirect) ? redirect : withBase(redirect, pathBase) }).end();
1193
+ return;
1194
+ }
1195
+ if (normalized === "/" || !findRoute(await loadProject(), pathname))
1196
+ return next();
1197
+ try {
1198
+ const raw = await readFile(path.join(vite.root, "index.html"), "utf8");
1199
+ const html = await server.transformIndexHtml(requested, raw);
1200
+ response.setHeader("content-type", "text/html; charset=utf-8");
1201
+ response.end(html);
1202
+ }
1203
+ catch (error) {
1204
+ next(error);
1205
+ }
1206
+ });
236
1207
  server.watcher.on("add", (file) => {
237
- if (["/pages/", "/components/", "/layouts/", "/islands/"].some((part) => file.includes(part))) {
1208
+ if (pageScripts.some(script => script.source === file) || options.serverComponents && (file.endsWith(".fragment.html") || options.serverComponents.references && file.startsWith(path.resolve(vite.root, options.serverComponents.references) + path.sep) || file === path.resolve(vite.root, options.serverComponents.server) || options.serverComponents.client && file === path.resolve(vite.root, options.serverComponents.client)) || ["/pages/", "/components/", "/layouts/", "/islands/", "/api/"].some((part) => file.replaceAll("\\", "/").includes(part))) {
238
1209
  void refresh(server).catch((error) => server.config.logger.error(String(error)));
239
1210
  }
240
1211
  });
241
1212
  server.watcher.on("unlink", (file) => {
242
- if (["/pages/", "/components/", "/layouts/", "/islands/"].some((part) => file.includes(part))) {
1213
+ if (pageScripts.some(script => script.source === file) || ["/pages/", "/components/", "/layouts/", "/islands/", "/api/"].some((part) => file.replaceAll("\\", "/").includes(part))) {
243
1214
  void refresh(server).catch((error) => server.config.logger.error(String(error)));
244
1215
  }
245
1216
  });
246
1217
  },
1218
+ buildStart() {
1219
+ buildFailed = false;
1220
+ bundleWritten = false;
1221
+ if (!nested && vite.command === "build") {
1222
+ releaseRuntimeHooks();
1223
+ releaseRuntimeHooks = runtimes?.registerNodeHooks() ?? (() => { });
1224
+ }
1225
+ },
1226
+ async generateBundle(_output, bundle) {
1227
+ if (nested || vite.build.ssr)
1228
+ return;
1229
+ if (runtimes?.enabled) {
1230
+ // A module assigned to a runtime but also imported by other code would run with two framework versions.
1231
+ for (const [file, runtime] of runtimes.assigned()) {
1232
+ const importers = this.getModuleInfo(file)?.importers ?? [];
1233
+ const foreign = importers.find(importer => runtimes.scopeOf(importer)?.key !== runtime);
1234
+ if (foreign)
1235
+ this.error(`${path.relative(vite.root, file)} is imported by ${runtime} islands and by ${path.relative(vite.root, foreign)}. Keep modules that use a framework runtime separate from other code.`);
1236
+ }
1237
+ }
1238
+ // Which files each island downloads, for `fuzor routes` (written outside the output directory).
1239
+ const chunks = Object.values(bundle).filter((item) => item.type === "chunk");
1240
+ inlineModuleFiles = chunks.map(chunk => chunk.fileName);
1241
+ const byName = new Map(chunks.map(chunk => [chunk.fileName, chunk]));
1242
+ const collect = (fileName, seen) => {
1243
+ if (seen.has(fileName))
1244
+ return;
1245
+ seen.add(fileName);
1246
+ for (const imported of byName.get(fileName)?.imports ?? [])
1247
+ collect(imported, seen);
1248
+ };
1249
+ const report = {};
1250
+ islandStyles = {};
1251
+ for (const island of islands) {
1252
+ const chunk = chunks.find(item => item.facadeModuleId === path.join(vite.root, island.file));
1253
+ if (!chunk)
1254
+ continue;
1255
+ const files = new Set();
1256
+ collect(chunk.fileName, files);
1257
+ const css = [...files].flatMap(file => [...(byName.get(file)?.viteMetadata?.importedCss ?? [])]);
1258
+ report[island.name] = { files: [...files], css: [...new Set(css)] };
1259
+ islandStyles[island.name] = report[island.name].css;
1260
+ }
1261
+ const file = path.join(vite.root, ".fuzor", `chunks-${target}${withServer ? "-server" : ""}.json`);
1262
+ await mkdir(path.dirname(file), { recursive: true });
1263
+ await writeFile(file, JSON.stringify({ inline, islands: Object.fromEntries(islands.map(module => [module.name, report[module.name]])) }, null, 2), "utf8");
1264
+ },
1265
+ buildEnd(error) { if (error)
1266
+ buildFailed = true; },
1267
+ // Errors while generating or writing chunks happen after buildEnd; only a written bundle is post-processed.
1268
+ renderError() { buildFailed = true; },
1269
+ writeBundle() { bundleWritten = true; },
247
1270
  async closeBundle() {
248
- if (vite.command !== "build")
1271
+ // Rollup still calls closeBundle after a failed build; post-processing would hide the real error.
1272
+ if (nested)
249
1273
  return;
250
- const outDir = path.resolve(vite.root, vite.build.outDir);
251
- if (target === "spa" && inline) {
252
- let html = await readFile(path.join(outDir, "index.html"), "utf8");
253
- const assetFiles = new Set();
254
- for (const match of html.matchAll(/<script\b[^>]*\bsrc="([^"]+)"[^>]*><\/script>/g)) {
255
- const url = match[1];
256
- if (!url.endsWith(".js"))
257
- continue;
258
- const file = path.join(outDir, url.replace(/^\//, ""));
259
- const source = await readFile(file, "utf8");
260
- html = html.replace(match[0], () => `<script type="module">${source.replace(/<\/script/gi, "<\\/script")}</script>`);
261
- assetFiles.add(file);
1274
+ try {
1275
+ if (vite.command !== "build")
1276
+ return;
1277
+ if (buildFailed || !bundleWritten)
1278
+ return;
1279
+ const outDir = path.resolve(vite.root, vite.build.outDir);
1280
+ const compiled = await loadProject();
1281
+ const artifact = { version: 1, buildId: viewBuildId, platform: profile.platform, mode: profile.mixed ? "mixed" : target, inline, backendRequired: compiled.routes.some(route => route.policy?.rendering === "request"), routes: compiled.routes.map(route => ({ path: route.path, ...route.policy, backendData: !!route.serverData, ...(route.requestPattern ? { requestPattern: route.requestPattern } : {}) })) };
1282
+ await mkdir(path.join(vite.root, ".fuzor"), { recursive: true });
1283
+ if (!inline)
1284
+ await writeFile(path.join(outDir, "fuzor.manifest.json"), JSON.stringify(artifact, null, 2) + "\n");
1285
+ if (target === "spa" && inline) {
1286
+ const inlined = await inlineDocumentAssets(await readFile(path.join(outDir, "index.html"), "utf8"), outDir, inlineModuleFiles);
1287
+ const html = inlined.html;
1288
+ const assetFiles = inlined.files;
1289
+ await writeFile(path.join(outDir, "index.html"), html, "utf8");
1290
+ for (const file of assetFiles)
1291
+ await unlink(file);
1292
+ const assetDir = path.join(outDir, "assets");
1293
+ try {
1294
+ const remaining = await readdir(assetDir);
1295
+ if (remaining.length > 0)
1296
+ throw new Error(`SPA inline build left external assets: ${remaining.join(", ")}`);
1297
+ await rmdir(assetDir);
1298
+ }
1299
+ catch (error) {
1300
+ if (error.code !== "ENOENT")
1301
+ throw error;
1302
+ }
1303
+ const remainingFiles = await readdir(outDir);
1304
+ if (remainingFiles.length !== 1 || remainingFiles[0] !== "index.html") {
1305
+ throw new Error(`An inline SPA build must be a single index.html, but these files are outside it: ${remainingFiles.filter((file) => file !== "index.html").join(", ")}. ` +
1306
+ "They usually come from public/, which Vite copies unchanged. Import images and fonts from source files instead (inline builds embed them as data URLs), remove the public files, or use the regular SPA build.");
1307
+ }
1308
+ if (profile.electron)
1309
+ await writeElectronScaffold(outDir);
1310
+ return;
262
1311
  }
263
- for (const match of html.matchAll(/<link\b[^>]*\brel="stylesheet"[^>]*\bhref="([^"]+)"[^>]*>/g)) {
264
- const file = path.join(outDir, match[1].replace(/^\//, ""));
265
- const source = await readFile(file, "utf8");
266
- html = html.replace(match[0], () => `<style>${source.replace(/<\/style/gi, "<\\/style")}</style>`);
267
- assetFiles.add(file);
1312
+ const styled = (html) => withIslandStyles(html, islandStyles, vite.base);
1313
+ const rootHtml = styled(await readFile(path.join(outDir, "index.html"), "utf8"));
1314
+ await writeFile(path.join(outDir, "index.html"), rootHtml, "utf8");
1315
+ if (withServer) {
1316
+ const serverDir = process.env.FUZOR_STAGE_DIR ? path.resolve(process.env.FUZOR_STAGE_DIR, profile.backendOutDir) : path.resolve(vite.root, profile.backendOutDir);
1317
+ const manifest = { ...serverManifest(compiled, target, rootHtml, pathBase, fallbacks(), styled, options.clientRoutes, `/${vite.build.assetsDir}/`, profile.mixed), buildId: viewBuildId };
1318
+ await mkdir(serverDir, { recursive: true });
1319
+ await writeFile(path.join(serverDir, "fuzor.manifest.json"), JSON.stringify({ ...artifact, clientDirectory: path.relative(serverDir, outDir).split(path.sep).join("/") }, null, 2) + "\n");
1320
+ const dataRoutes = compiled.routes.filter(route => route.serverData);
1321
+ const refs = options.serverComponents?.references ? await references() : undefined;
1322
+ if (!dataRoutes.length && !apiFiles.length && !options.serverComponents) {
1323
+ await writeFile(path.join(serverDir, "entry.mjs"), `import { createServerHandler } from "fuzor/server";\n` +
1324
+ `export const manifest = ${JSON.stringify(manifest)};\n` +
1325
+ `export const handler = createServerHandler(manifest);\n`, "utf8");
1326
+ }
1327
+ else {
1328
+ // Server modules are bundled for Node; documents remain precompiled strings in the manifest.
1329
+ const files = [...new Set(dataRoutes.map(route => route.serverData))];
1330
+ const entryId = "virtual:fuzor/server-entry";
1331
+ const code = [
1332
+ `import { createServerHandler, isServerData } from "fuzor/server";`,
1333
+ ...(options.serverComponents ? [`import suppliedViews from ${JSON.stringify(path.resolve(vite.root, options.serverComponents.server))};`, `const views = { ...suppliedViews${refs ? `, manifest: ${JSON.stringify({ buildId: viewBuildId, templates: refs.templates })}, components: ${JSON.stringify(refs.clients.map(ref => ref.id))}, handlers: ${JSON.stringify([...refs.handlers.map(ref => ref.id), ...refs.closures.map(ref => ref.id)])}` : ""} };`, `if (JSON.stringify(Object.keys(views.routes).sort()) !== ${JSON.stringify(JSON.stringify([...options.serverComponents.routes].sort()))}) throw new Error("Server view routes must match serverComponents.routes.");`] : []),
1334
+ ...files.map((file, index) => `import data${index} from ${JSON.stringify(file)};`),
1335
+ ...apiFiles.map((route, index) => `import * as api${index} from ${JSON.stringify(route.file)};`),
1336
+ `const modules = [${files.map((_, index) => `data${index}`).join(", ")}];`,
1337
+ `const sources = ${JSON.stringify(files.map(file => path.relative(vite.root, file).split(path.sep).join("/")))};`,
1338
+ `modules.forEach((module, index) => { if (!isServerData(module)) throw new Error(sources[index] + " must export default defineServerData(...) from \\"fuzor/server\\"."); });`,
1339
+ `export const manifest = ${JSON.stringify(manifest)};`,
1340
+ `const routes = ${JSON.stringify(dataRoutes.map(route => [route.path, files.indexOf(route.serverData), route.params ?? null]))};`,
1341
+ `const api = [${apiFiles.map((route, index) => `{ pattern: ${JSON.stringify(route.pattern)}, segments: ${JSON.stringify(route.segments)}, source: ${JSON.stringify(route.relative)}, module: api${index} }`).join(", ")}];`,
1342
+ `export const handler = createServerHandler(manifest, { data: Object.fromEntries(routes.map(([route, index, params]) => [route, params ? { data: modules[index], params } : { data: modules[index] }])), api${options.serverComponents ? `, views: { ...views, manifest: { ...views.manifest, buildId: ${JSON.stringify(viewBuildId)} }, documentPatterns:${JSON.stringify(manifest.requestPatterns ?? {})}, document: ${JSON.stringify(serverViewDocument(rootHtml))}, documents:${JSON.stringify(Object.fromEntries(Object.entries("documents" in manifest ? manifest.documents : manifest.routeDocuments ?? {}).map(([route, html]) => [route, serverViewDocument(html)])))} }` : ""} });`
1343
+ ].join("\n");
1344
+ await nestedServer.run(true, () => viteBuild({
1345
+ root: vite.root, mode: vite.mode, configFile: vite.configFile ?? false, logLevel: "error", publicDir: false,
1346
+ // One runtime copy: the entry and server modules must share fuzor/server and effect from node_modules.
1347
+ ssr: { external: ["fuzor", "effect"] },
1348
+ plugins: [compiledFragmentsPlugin(), workflowPlugin(), ...(refs ? [{ name: "fuzor:server-references", load: (id) => referenceStub(id, refs) }] : []), { name: "fuzor:server-entry", resolveId: id => id === entryId ? `\0${entryId}` : undefined, load: id => id === `\0${entryId}` ? code : undefined }],
1349
+ build: { ssr: true, outDir: serverDir, emptyOutDir: false, copyPublicDir: false, minify: false,
1350
+ rollupOptions: { input: entryId, output: { entryFileNames: "entry.mjs", chunkFileNames: "chunks/[name]-[hash].mjs", format: "es" } } }
1351
+ }));
1352
+ }
1353
+ // The same finished documents are also written to client/ below, so it can be served by a CDN or
1354
+ // static host with only /api and server data requests reaching the server.
1355
+ if (profile.adapter === "cloudflare")
1356
+ await writeCloudflareOutput(serverDir, vite.root, target, pathBase, outDir, [...compiled.routes.filter(route => route.policy?.rendering === "request").map(route => route.requestPattern ? route.requestPattern.slice(0, route.requestPattern.indexOf(":")) + "*" : route.path), ...(options.serverComponents?.routes ?? []).map(pattern => pattern.includes(":") ? pattern.slice(0, pattern.indexOf(":")) + "*" : pattern)], path.relative(path.resolve(vite.root, profile.backendOutDir), process.env.FUZOR_STAGE_DIR && outDir.startsWith(path.resolve(process.env.FUZOR_STAGE_DIR) + path.sep) ? path.resolve(vite.root, path.relative(process.env.FUZOR_STAGE_DIR, outDir)) : outDir).split(path.sep).join("/"));
268
1357
  }
269
- await writeFile(path.join(outDir, "index.html"), html, "utf8");
270
- for (const file of assetFiles)
271
- await unlink(file);
272
- const assetDir = path.join(outDir, "assets");
273
- try {
274
- const remaining = await readdir(assetDir);
275
- if (remaining.length > 0)
276
- throw new Error(`SPA inline build left external assets: ${remaining.join(", ")}`);
277
- await rmdir(assetDir);
1358
+ const index = searchIndex(compiled, options.searchIndex);
1359
+ if (index)
1360
+ await writeFile(path.join(outDir, "search-index.json"), index, "utf8");
1361
+ const redirects = Object.entries(compiled.redirects ?? {}).map(([from, to]) => [from, /^https?:\/\//i.test(to) ? to : withBase(to, pathBase)]);
1362
+ if (redirects.length) {
1363
+ await writeFile(path.join(outDir, "_redirects"), redirects.map(([from, to]) => `${withBase(from, pathBase)} ${to} 308`).join("\n") + "\n", "utf8");
278
1364
  }
279
- catch (error) {
280
- if (error.code !== "ENOENT")
281
- throw error;
1365
+ // Static hosts read cache rules from _headers (Cloudflare, Netlify); servers send the same values.
1366
+ const lifetimes = compiled.routes.filter(route => route.metadata?.revalidate);
1367
+ if (target === "mpa" && lifetimes.length) {
1368
+ await writeFile(path.join(outDir, "_headers"), lifetimes.map(route => {
1369
+ const seconds = route.metadata.revalidate;
1370
+ return `${withBase(route.path, pathBase)}\n Cache-Control: public, max-age=0, s-maxage=${seconds}, stale-while-revalidate=${seconds}\n`;
1371
+ }).join(""), "utf8");
282
1372
  }
283
- const remainingFiles = await readdir(outDir);
284
- if (remainingFiles.length !== 1 || remainingFiles[0] !== "index.html") {
285
- throw new Error(`SPA inline build left external files: ${remainingFiles.filter((file) => file !== "index.html").join(", ")}`);
1373
+ if (target === "spa")
1374
+ return;
1375
+ for (const [from, to] of redirects) {
1376
+ const outputFile = path.join(outDir, decodeURIComponent(from.slice(1)), "index.html");
1377
+ await mkdir(path.dirname(outputFile), { recursive: true });
1378
+ await writeFile(outputFile, redirectDocument(to), "utf8");
286
1379
  }
287
- return;
288
- }
289
- const compiled = await loadProject();
290
- const rootHtml = await readFile(path.join(outDir, "index.html"), "utf8");
291
- if (withServer) {
292
- const serverDir = path.resolve(outDir, "../server");
293
- const notFoundDocument = replaceOutlet(rootHtml, '<fuzor-router data-fuzor-not-found><h1>Not found</h1></fuzor-router>');
294
- const manifest = target === "spa"
295
- ? { document: rootHtml, routes: Object.fromEntries(compiled.routes.map((route) => [route.path, true])), notFoundDocument }
296
- : { documents: Object.fromEntries(compiled.routes.map((route) => [route.path, replaceOutlet(rootHtml, `<fuzor-router>${route.html}</fuzor-router>`)])), notFoundDocument };
297
- await mkdir(serverDir, { recursive: true });
298
- await writeFile(path.join(serverDir, "entry.mjs"), `import { createServerHandler } from "fuzor/server";\n` +
299
- `export const manifest = ${JSON.stringify(manifest)};\n` +
300
- `export const handler = createServerHandler(manifest);\n`, "utf8");
301
- await unlink(path.join(outDir, "index.html"));
302
- return;
1380
+ // Static hosts such as Cloudflare Pages and Netlify serve the nearest 404.html for a missing URL.
1381
+ const { notFoundDocument, notFoundDocuments } = serverManifest(compiled, "mpa", rootHtml, pathBase, fallbacks(), styled);
1382
+ for (const [scope, document] of Object.entries(notFoundDocuments ?? { "/": notFoundDocument })) {
1383
+ const outputFile = path.join(outDir, decodeURIComponent(scope.slice(1)), "404.html");
1384
+ await mkdir(path.dirname(outputFile), { recursive: true });
1385
+ await writeFile(outputFile, document, "utf8");
1386
+ }
1387
+ for (const route of compiled.routes) {
1388
+ if (route.path === "/" || route.policy?.rendering === "request")
1389
+ continue;
1390
+ const outputFile = path.join(outDir, decodeURIComponent(route.path.slice(1)), "index.html");
1391
+ await mkdir(path.dirname(outputFile), { recursive: true });
1392
+ await writeFile(outputFile, styled(applyDocumentMetadata(replaceOutlet(rootHtml, outletFor(compiled, "mpa", route.path, fallbacks(), profile.mixed)), pageHead(shellHead, route.metadata ?? {}))), "utf8");
1393
+ }
1394
+ if (compiled.routes.find(route => route.path === "/")?.policy?.rendering === "request")
1395
+ await unlink(path.join(outDir, "index.html"));
303
1396
  }
304
- if (target === "spa")
305
- return;
306
- for (const route of compiled.routes) {
307
- if (route.path === "/")
308
- continue;
309
- const outputFile = path.join(outDir, route.path.slice(1), "index.html");
310
- await mkdir(path.dirname(outputFile), { recursive: true });
311
- await writeFile(outputFile, replaceOutlet(rootHtml, outletFor(compiled, "mpa", route.path)), "utf8");
1397
+ finally {
1398
+ compilation?.abort();
1399
+ releaseRuntimeHooks();
312
1400
  }
313
1401
  },
314
1402
  async handleHotUpdate(context) {
315
- if (["/pages/", "/components/", "/layouts/", "/islands/"].some((part) => context.file.includes(part))) {
1403
+ if (nested)
1404
+ return;
1405
+ const file = context.file.replaceAll("\\", "/");
1406
+ if (pageScripts.some(script => script.source === file) || options.serverComponents && (file.endsWith(".fragment.html") || options.serverComponents.references && file.startsWith(path.resolve(vite.root, options.serverComponents.references) + path.sep) || file === path.resolve(vite.root, options.serverComponents.server) || options.serverComponents.client && file === path.resolve(vite.root, options.serverComponents.client)) || ["/pages/", "/components/", "/layouts/", "/islands/", "/api/"].some((part) => file.includes(part))) {
1407
+ const environment = context.environment?.name;
1408
+ if (environment)
1409
+ invalidateEnvironmentModule(context.server, resolvedVirtualId, environment, environmentApiEnabled);
316
1410
  await refresh(context.server);
317
1411
  }
318
1412
  }