meno-core 1.0.53 → 1.0.54

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 (387) hide show
  1. package/.claude/settings.local.json +1 -3
  2. package/bin/cli.ts +48 -57
  3. package/build-astro.ts +131 -113
  4. package/build-next.ts +109 -96
  5. package/build-static.test.ts +39 -10
  6. package/build-static.ts +120 -122
  7. package/dist/bin/cli.js +34 -38
  8. package/dist/bin/cli.js.map +2 -2
  9. package/dist/build-static.js +12 -11
  10. package/dist/chunks/chunk-2AR55GYH.js +42 -0
  11. package/dist/chunks/chunk-2AR55GYH.js.map +7 -0
  12. package/dist/chunks/{chunk-IGYR22T6.js → chunk-2FN4UOVO.js} +512 -239
  13. package/dist/chunks/chunk-2FN4UOVO.js.map +7 -0
  14. package/dist/chunks/chunk-3XER4E5W.js +168 -0
  15. package/dist/chunks/chunk-3XER4E5W.js.map +7 -0
  16. package/dist/chunks/{chunk-X754AHS5.js → chunk-5ETZFREW.js} +9 -12
  17. package/dist/chunks/chunk-5ETZFREW.js.map +7 -0
  18. package/dist/chunks/{chunk-2MHDV5BF.js → chunk-7E4IF5L7.js} +15 -21
  19. package/dist/chunks/chunk-7E4IF5L7.js.map +7 -0
  20. package/dist/chunks/{chunk-JGWFTO6P.js → chunk-7HWQUVTU.js} +1578 -1349
  21. package/dist/chunks/chunk-7HWQUVTU.js.map +7 -0
  22. package/dist/chunks/{chunk-O3NAGJP4.js → chunk-AE3QK5QW.js} +110 -21
  23. package/dist/chunks/chunk-AE3QK5QW.js.map +7 -0
  24. package/dist/chunks/{chunk-GZHGVVW3.js → chunk-F6KTJYGV.js} +7 -7
  25. package/dist/chunks/chunk-F6KTJYGV.js.map +7 -0
  26. package/dist/chunks/{chunk-WQFG7PAH.js → chunk-FZITJSSS.js} +2 -6
  27. package/dist/chunks/chunk-FZITJSSS.js.map +7 -0
  28. package/dist/chunks/{chunk-QB2LNO4W.js → chunk-GSYYA5GX.js} +2 -2
  29. package/dist/chunks/chunk-GSYYA5GX.js.map +7 -0
  30. package/dist/chunks/{chunk-YBLHKYFF.js → chunk-HIZMY3EP.js} +1 -1
  31. package/dist/chunks/chunk-HIZMY3EP.js.map +7 -0
  32. package/dist/chunks/{chunk-AZQYF6KE.js → chunk-I2WEGYA7.js} +41 -176
  33. package/dist/chunks/chunk-I2WEGYA7.js.map +7 -0
  34. package/dist/chunks/{chunk-I7YIGZXT.js → chunk-JNO3CNLJ.js} +6 -9
  35. package/dist/chunks/chunk-JNO3CNLJ.js.map +7 -0
  36. package/dist/chunks/{chunk-UB44F4Z2.js → chunk-NVRBTSQG.js} +2 -4
  37. package/dist/chunks/chunk-NVRBTSQG.js.map +7 -0
  38. package/dist/chunks/{chunk-JGP5A3Y5.js → chunk-Q4OBWKXG.js} +40 -33
  39. package/dist/chunks/chunk-Q4OBWKXG.js.map +7 -0
  40. package/dist/chunks/{chunk-R6XHAFBF.js → chunk-QTE32Y53.js} +250 -242
  41. package/dist/chunks/chunk-QTE32Y53.js.map +7 -0
  42. package/dist/chunks/{chunk-H3GJ4H2U.js → chunk-STDY3OVM.js} +214 -85
  43. package/dist/chunks/chunk-STDY3OVM.js.map +7 -0
  44. package/dist/chunks/configService-PRJZF7Y6.js +14 -0
  45. package/dist/chunks/{constants-STK2YBIW.js → constants-KIQEYMAM.js} +2 -2
  46. package/dist/chunks/{fs-JGINUXGL.js → fs-ZI5JEU7V.js} +2 -2
  47. package/dist/entries/server-router.js +14 -19
  48. package/dist/entries/server-router.js.map +2 -2
  49. package/dist/lib/client/index.js +638 -332
  50. package/dist/lib/client/index.js.map +2 -2
  51. package/dist/lib/server/index.js +177 -235
  52. package/dist/lib/server/index.js.map +2 -2
  53. package/dist/lib/shared/index.js +80 -44
  54. package/dist/lib/shared/index.js.map +2 -2
  55. package/dist/lib/shared/richtext/index.js +1 -1
  56. package/dist/lib/test-utils/index.js +38 -60
  57. package/dist/lib/test-utils/index.js.map +2 -2
  58. package/entries/client-router.tsx +10 -8
  59. package/entries/server-router.tsx +1 -7
  60. package/lib/client/ClientInitializer.ts +8 -8
  61. package/lib/client/ErrorBoundary.test.tsx +146 -143
  62. package/lib/client/ErrorBoundary.tsx +175 -127
  63. package/lib/client/componentRegistry.test.ts +96 -108
  64. package/lib/client/componentRegistry.ts +1 -2
  65. package/lib/client/contexts/ThemeContext.tsx +3 -2
  66. package/lib/client/core/ComponentBuilder.test.ts +513 -560
  67. package/lib/client/core/ComponentBuilder.ts +318 -146
  68. package/lib/client/core/ComponentRenderer.test.tsx +1 -2
  69. package/lib/client/core/ComponentRenderer.tsx +46 -33
  70. package/lib/client/core/builders/embedBuilder.ts +241 -53
  71. package/lib/client/core/builders/linkBuilder.ts +71 -44
  72. package/lib/client/core/builders/linkNodeBuilder.ts +78 -53
  73. package/lib/client/core/builders/listBuilder.ts +115 -86
  74. package/lib/client/core/builders/localeListBuilder.ts +95 -60
  75. package/lib/client/core/builders/types.ts +5 -5
  76. package/lib/client/core/cmsTemplateProcessor.ts +7 -7
  77. package/lib/client/elementRegistry.ts +3 -3
  78. package/lib/client/fontFamiliesService.test.ts +2 -10
  79. package/lib/client/fontFamiliesService.ts +3 -3
  80. package/lib/client/hmr/HMRManager.tsx +8 -0
  81. package/lib/client/hmrCssReload.ts +14 -8
  82. package/lib/client/hmrWebSocket.ts +9 -14
  83. package/lib/client/hooks/useColorVariables.test.ts +21 -21
  84. package/lib/client/hooks/useColorVariables.ts +12 -10
  85. package/lib/client/hooks/usePropertyAutocomplete.ts +3 -5
  86. package/lib/client/hooks/useVariables.ts +4 -4
  87. package/lib/client/hydration/HydrationUtils.test.ts +24 -25
  88. package/lib/client/hydration/HydrationUtils.ts +3 -4
  89. package/lib/client/i18nConfigService.test.ts +2 -7
  90. package/lib/client/i18nConfigService.ts +2 -2
  91. package/lib/client/meno-filter/MenoFilter.test.ts +19 -21
  92. package/lib/client/meno-filter/MenoFilter.ts +5 -9
  93. package/lib/client/meno-filter/bindings.ts +15 -40
  94. package/lib/client/meno-filter/init.ts +1 -1
  95. package/lib/client/meno-filter/renderer.ts +23 -29
  96. package/lib/client/meno-filter/script.generated.ts +1 -3
  97. package/lib/client/meno-filter/ui.ts +3 -5
  98. package/lib/client/meno-filter/updates.ts +15 -21
  99. package/lib/client/navigation.test.ts +159 -159
  100. package/lib/client/navigation.ts +0 -1
  101. package/lib/client/responsiveStyleResolver.test.ts +230 -228
  102. package/lib/client/responsiveStyleResolver.ts +13 -16
  103. package/lib/client/routing/RouteLoader.test.ts +23 -24
  104. package/lib/client/routing/RouteLoader.ts +22 -35
  105. package/lib/client/routing/Router.tsx +31 -3
  106. package/lib/client/scripts/ScriptExecutor.test.ts +157 -158
  107. package/lib/client/scripts/ScriptExecutor.ts +15 -33
  108. package/lib/client/services/PrefetchService.test.ts +2 -2
  109. package/lib/client/services/PrefetchService.ts +10 -24
  110. package/lib/client/styleProcessor.test.ts +9 -9
  111. package/lib/client/styleProcessor.ts +18 -15
  112. package/lib/client/styles/StyleInjector.test.ts +122 -115
  113. package/lib/client/styles/StyleInjector.ts +9 -6
  114. package/lib/client/styles/UtilityClassCollector.ts +19 -26
  115. package/lib/client/styles/cspNonce.test.ts +2 -5
  116. package/lib/client/templateEngine.test.ts +554 -482
  117. package/lib/client/templateEngine.ts +200 -64
  118. package/lib/client/theme.ts +0 -1
  119. package/lib/client/utils/toast.ts +0 -1
  120. package/lib/server/__integration__/api-routes.test.ts +8 -4
  121. package/lib/server/__integration__/cms-integration.test.ts +1 -4
  122. package/lib/server/__integration__/server-lifecycle.test.ts +2 -5
  123. package/lib/server/__integration__/ssr-rendering.test.ts +47 -37
  124. package/lib/server/__integration__/static-assets.test.ts +1 -1
  125. package/lib/server/__integration__/test-helpers.ts +84 -70
  126. package/lib/server/ab/generateFunctions.ts +12 -10
  127. package/lib/server/astro/cmsPageEmitter.ts +23 -38
  128. package/lib/server/astro/componentEmitter.ts +25 -36
  129. package/lib/server/astro/cssCollector.ts +10 -26
  130. package/lib/server/astro/nodeToAstro.test.ts +1750 -30
  131. package/lib/server/astro/nodeToAstro.ts +198 -187
  132. package/lib/server/astro/normalizeOrphanTemplateProps.test.ts +105 -109
  133. package/lib/server/astro/normalizeOrphanTemplateProps.ts +4 -12
  134. package/lib/server/astro/pageEmitter.ts +9 -13
  135. package/lib/server/astro/tailwindMapper.test.ts +10 -37
  136. package/lib/server/astro/tailwindMapper.ts +33 -40
  137. package/lib/server/astro/templateTransformer.ts +14 -17
  138. package/lib/server/createServer.ts +5 -17
  139. package/lib/server/cssGenerator.test.ts +35 -44
  140. package/lib/server/cssGenerator.ts +6 -17
  141. package/lib/server/fileWatcher.test.ts +124 -10
  142. package/lib/server/fileWatcher.ts +124 -118
  143. package/lib/server/index.ts +7 -1
  144. package/lib/server/jsonLoader.test.ts +39 -2
  145. package/lib/server/jsonLoader.ts +33 -31
  146. package/lib/server/middleware/cors.test.ts +20 -20
  147. package/lib/server/middleware/cors.ts +28 -4
  148. package/lib/server/middleware/errorHandler.test.ts +5 -3
  149. package/lib/server/middleware/errorHandler.ts +3 -8
  150. package/lib/server/middleware/index.ts +0 -1
  151. package/lib/server/middleware/logger.test.ts +7 -5
  152. package/lib/server/middleware/logger.ts +10 -22
  153. package/lib/server/pageCache.test.ts +76 -77
  154. package/lib/server/pageCache.ts +0 -1
  155. package/lib/server/projectContext.ts +4 -3
  156. package/lib/server/providers/fileSystemCMSProvider.test.ts +124 -95
  157. package/lib/server/providers/fileSystemCMSProvider.ts +35 -20
  158. package/lib/server/providers/fileSystemPageProvider.test.ts +84 -0
  159. package/lib/server/providers/fileSystemPageProvider.ts +31 -12
  160. package/lib/server/routes/api/cms.test.ts +26 -14
  161. package/lib/server/routes/api/cms.ts +9 -14
  162. package/lib/server/routes/api/components.ts +30 -34
  163. package/lib/server/routes/api/config.ts +0 -1
  164. package/lib/server/routes/api/core-routes.ts +47 -74
  165. package/lib/server/routes/api/functions.ts +8 -16
  166. package/lib/server/routes/api/index.ts +3 -6
  167. package/lib/server/routes/api/pages.ts +8 -11
  168. package/lib/server/routes/api/shared.test.ts +1 -1
  169. package/lib/server/routes/api/shared.ts +12 -9
  170. package/lib/server/routes/api/variables.test.ts +1 -3
  171. package/lib/server/routes/api/variables.ts +1 -1
  172. package/lib/server/routes/index.ts +23 -26
  173. package/lib/server/routes/pages.ts +34 -29
  174. package/lib/server/routes/static.ts +16 -4
  175. package/lib/server/runtime/bundler.ts +47 -32
  176. package/lib/server/runtime/fs.ts +3 -13
  177. package/lib/server/runtime/httpServer.ts +5 -9
  178. package/lib/server/services/ColorService.ts +32 -27
  179. package/lib/server/services/EnumService.test.ts +2 -6
  180. package/lib/server/services/EnumService.ts +7 -2
  181. package/lib/server/services/VariableService.test.ts +1 -5
  182. package/lib/server/services/VariableService.ts +6 -1
  183. package/lib/server/services/cmsService.test.ts +116 -78
  184. package/lib/server/services/cmsService.ts +24 -54
  185. package/lib/server/services/componentService.test.ts +122 -36
  186. package/lib/server/services/componentService.ts +54 -38
  187. package/lib/server/services/configService.test.ts +9 -31
  188. package/lib/server/services/configService.ts +20 -27
  189. package/lib/server/services/fileWatcherService.ts +40 -6
  190. package/lib/server/services/index.ts +0 -1
  191. package/lib/server/services/pageService.test.ts +1 -3
  192. package/lib/server/services/pageService.ts +14 -13
  193. package/lib/server/ssr/attributeBuilder.ts +16 -6
  194. package/lib/server/ssr/buildErrorOverlay.ts +11 -12
  195. package/lib/server/ssr/clientDataInjector.ts +7 -21
  196. package/lib/server/ssr/cmsSSRProcessor.ts +3 -6
  197. package/lib/server/ssr/cssCollector.ts +1 -1
  198. package/lib/server/ssr/errorOverlay.test.ts +1 -1
  199. package/lib/server/ssr/errorOverlay.ts +3 -9
  200. package/lib/server/ssr/htmlGenerator.nonce.test.ts +3 -9
  201. package/lib/server/ssr/htmlGenerator.test.ts +120 -43
  202. package/lib/server/ssr/htmlGenerator.ts +120 -85
  203. package/lib/server/ssr/imageMetadata.test.ts +3 -1
  204. package/lib/server/ssr/imageMetadata.ts +25 -19
  205. package/lib/server/ssr/jsCollector.test.ts +3 -13
  206. package/lib/server/ssr/jsCollector.ts +3 -8
  207. package/lib/server/ssr/liveReloadIntegration.test.ts +69 -28
  208. package/lib/server/ssr/metaTagGenerator.ts +2 -2
  209. package/lib/server/ssr/ssrRenderer.branches.test.ts +1103 -0
  210. package/lib/server/ssr/ssrRenderer.test.ts +196 -246
  211. package/lib/server/ssr/ssrRenderer.ts +609 -225
  212. package/lib/server/ssrRenderer.test.ts +1044 -950
  213. package/lib/server/utils/jsonLineMapper.test.ts +28 -28
  214. package/lib/server/utils/jsonLineMapper.ts +1 -1
  215. package/lib/server/validateStyleCoverage.ts +18 -20
  216. package/lib/server/webflow/buildWebflow.ts +41 -53
  217. package/lib/server/webflow/nodeToWebflow.test.ts +150 -218
  218. package/lib/server/webflow/nodeToWebflow.ts +195 -258
  219. package/lib/server/webflow/styleMapper.test.ts +15 -56
  220. package/lib/server/webflow/styleMapper.ts +33 -41
  221. package/lib/server/webflow/types.ts +1 -8
  222. package/lib/server/websocketManager.ts +16 -19
  223. package/lib/shared/attributeNodeUtils.test.ts +15 -15
  224. package/lib/shared/attributeNodeUtils.ts +5 -12
  225. package/lib/shared/breakpoints.ts +4 -11
  226. package/lib/shared/cmsQueryParser.test.ts +50 -42
  227. package/lib/shared/cmsQueryParser.ts +49 -31
  228. package/lib/shared/colorVariableUtils.test.ts +5 -5
  229. package/lib/shared/colorVariableUtils.ts +3 -8
  230. package/lib/shared/componentRefs.ts +1 -5
  231. package/lib/shared/constants.test.ts +3 -3
  232. package/lib/shared/constants.ts +4 -8
  233. package/lib/shared/cssGeneration.test.ts +262 -144
  234. package/lib/shared/cssGeneration.ts +189 -516
  235. package/lib/shared/cssNamedColors.ts +152 -30
  236. package/lib/shared/cssProperties.test.ts +5 -6
  237. package/lib/shared/cssProperties.ts +296 -112
  238. package/lib/shared/elementClassName.test.ts +109 -109
  239. package/lib/shared/elementClassName.ts +1 -1
  240. package/lib/shared/elementUtils.ts +12 -16
  241. package/lib/shared/errorLogger.ts +2 -10
  242. package/lib/shared/errors.test.ts +2 -13
  243. package/lib/shared/errors.ts +2 -8
  244. package/lib/shared/expressionEvaluator.test.ts +119 -0
  245. package/lib/shared/expressionEvaluator.ts +43 -24
  246. package/lib/shared/fontLoader.test.ts +19 -5
  247. package/lib/shared/friendlyError.ts +2 -3
  248. package/lib/shared/gradientUtils.test.ts +1 -5
  249. package/lib/shared/gradientUtils.ts +2 -6
  250. package/lib/shared/hrefRefs.ts +2 -10
  251. package/lib/shared/i18n.test.ts +1 -1
  252. package/lib/shared/i18n.ts +13 -34
  253. package/lib/shared/index.ts +4 -0
  254. package/lib/shared/inlineSvgStyleRules.ts +2 -4
  255. package/lib/shared/interactiveStyleMappings.test.ts +11 -33
  256. package/lib/shared/interactiveStyleMappings.ts +9 -16
  257. package/lib/shared/interactiveStyles.test.ts +165 -188
  258. package/lib/shared/interfaces/contentProvider.ts +1 -1
  259. package/lib/shared/itemTemplateUtils.test.ts +6 -12
  260. package/lib/shared/itemTemplateUtils.ts +19 -35
  261. package/lib/shared/jsonRepair.ts +8 -2
  262. package/lib/shared/libraryLoader.test.ts +15 -49
  263. package/lib/shared/libraryLoader.ts +7 -22
  264. package/lib/shared/netlifyLocale404.test.ts +179 -0
  265. package/lib/shared/netlifyLocale404.ts +110 -0
  266. package/lib/shared/nodeUtils.test.ts +24 -16
  267. package/lib/shared/nodeUtils.ts +49 -19
  268. package/lib/shared/pathArrayUtils.test.ts +1 -2
  269. package/lib/shared/pathArrayUtils.ts +1 -1
  270. package/lib/shared/pathSecurity.ts +1 -1
  271. package/lib/shared/pathUtils.test.ts +4 -6
  272. package/lib/shared/pathUtils.ts +42 -48
  273. package/lib/shared/paths/Path.test.ts +2 -2
  274. package/lib/shared/paths/Path.ts +0 -1
  275. package/lib/shared/paths/PathConverter.test.ts +1 -1
  276. package/lib/shared/paths/PathConverter.ts +14 -17
  277. package/lib/shared/paths/PathUtils.ts +9 -10
  278. package/lib/shared/paths/PathValidator.test.ts +2 -15
  279. package/lib/shared/paths/PathValidator.ts +11 -9
  280. package/lib/shared/paths/index.ts +1 -2
  281. package/lib/shared/propResolver.test.ts +240 -244
  282. package/lib/shared/propResolver.ts +14 -25
  283. package/lib/shared/pxToRem.test.ts +7 -6
  284. package/lib/shared/pxToRem.ts +2 -5
  285. package/lib/shared/registry/BaseNodeTypeRegistry.test.ts +9 -5
  286. package/lib/shared/registry/ClientRegistry.ts +0 -1
  287. package/lib/shared/registry/ComponentRegistry.test.ts +43 -29
  288. package/lib/shared/registry/ComponentRegistry.ts +9 -11
  289. package/lib/shared/registry/NodeTypeDefinition.ts +15 -8
  290. package/lib/shared/registry/RegistryManager.ts +1 -2
  291. package/lib/shared/registry/SSRRegistry.ts +0 -1
  292. package/lib/shared/registry/createNodeType.ts +7 -9
  293. package/lib/shared/registry/defineNodeType.ts +2 -6
  294. package/lib/shared/registry/index.ts +0 -1
  295. package/lib/shared/registry/nodeTypes/ComponentInstanceNodeType.ts +14 -15
  296. package/lib/shared/registry/nodeTypes/EmbedNodeType.ts +18 -11
  297. package/lib/shared/registry/nodeTypes/HtmlNodeType.ts +47 -18
  298. package/lib/shared/registry/nodeTypes/LinkNodeType.ts +21 -19
  299. package/lib/shared/registry/nodeTypes/ListNodeType.ts +78 -74
  300. package/lib/shared/registry/nodeTypes/LocaleListNodeType.ts +27 -21
  301. package/lib/shared/registry/nodeTypes/SlotMarkerType.ts +6 -7
  302. package/lib/shared/registry/nodeTypes/index.ts +10 -2
  303. package/lib/shared/responsiveScaling.test.ts +15 -31
  304. package/lib/shared/responsiveScaling.ts +55 -37
  305. package/lib/shared/responsiveStyleUtils.ts +11 -13
  306. package/lib/shared/richtext/htmlToTiptap.test.ts +23 -14
  307. package/lib/shared/richtext/htmlToTiptap.ts +1 -3
  308. package/lib/shared/richtext/tiptapToHtml.test.ts +5 -6
  309. package/lib/shared/richtext/types.ts +1 -8
  310. package/lib/shared/slugTranslator.test.ts +13 -13
  311. package/lib/shared/slugTranslator.ts +12 -16
  312. package/lib/shared/slugify.ts +9 -15
  313. package/lib/shared/styleNodeUtils.test.ts +8 -8
  314. package/lib/shared/styleNodeUtils.ts +5 -10
  315. package/lib/shared/styleUtils.test.ts +87 -61
  316. package/lib/shared/styleUtils.ts +5 -6
  317. package/lib/shared/themeDefaults.test.ts +11 -11
  318. package/lib/shared/themeDefaults.ts +3 -4
  319. package/lib/shared/tree/PathBuilder.test.ts +62 -138
  320. package/lib/shared/tree/PathBuilder.ts +49 -39
  321. package/lib/shared/treePathUtils.test.ts +2 -10
  322. package/lib/shared/treePathUtils.ts +54 -59
  323. package/lib/shared/types/api.ts +1 -2
  324. package/lib/shared/types/cms.ts +25 -21
  325. package/lib/shared/types/comment.ts +49 -16
  326. package/lib/shared/types/components.ts +27 -25
  327. package/lib/shared/types/errors.test.ts +1 -6
  328. package/lib/shared/types/errors.ts +3 -7
  329. package/lib/shared/types/experiments.ts +28 -28
  330. package/lib/shared/types/index.ts +2 -2
  331. package/lib/shared/types/styles.ts +0 -1
  332. package/lib/shared/types/variables.test.ts +4 -13
  333. package/lib/shared/types/variables.ts +48 -27
  334. package/lib/shared/types.ts +1 -2
  335. package/lib/shared/utilityClassConfig.ts +648 -321
  336. package/lib/shared/utilityClassMapper.test.ts +203 -92
  337. package/lib/shared/utilityClassMapper.ts +188 -246
  338. package/lib/shared/utilityClassNames.ts +326 -0
  339. package/lib/shared/utils.test.ts +2 -10
  340. package/lib/shared/utils.ts +19 -10
  341. package/lib/shared/validation/cmsValidators.ts +2 -1
  342. package/lib/shared/validation/commentValidators.test.ts +53 -0
  343. package/lib/shared/validation/commentValidators.ts +12 -1
  344. package/lib/shared/validation/propValidator.test.ts +18 -20
  345. package/lib/shared/validation/propValidator.ts +12 -17
  346. package/lib/shared/validation/schemas.test.ts +24 -33
  347. package/lib/shared/validation/schemas.ts +469 -344
  348. package/lib/shared/validation/validators.test.ts +1 -6
  349. package/lib/shared/validation/validators.ts +89 -68
  350. package/lib/shared/viewportUnits.integration.test.ts +14 -10
  351. package/lib/shared/viewportUnits.test.ts +11 -23
  352. package/lib/test-utils/dom-setup.ts +1 -1
  353. package/lib/test-utils/factories/ConsoleMockFactory.ts +3 -7
  354. package/lib/test-utils/factories/DomMockFactory.ts +7 -19
  355. package/lib/test-utils/factories/EventMockFactory.ts +7 -13
  356. package/lib/test-utils/factories/FetchMockFactory.ts +39 -57
  357. package/lib/test-utils/factories/ServerMockFactory.ts +5 -9
  358. package/lib/test-utils/factories/StoreMockFactory.ts +14 -25
  359. package/lib/test-utils/fixtures.ts +45 -45
  360. package/lib/test-utils/helpers/asyncHelpers.test.ts +15 -18
  361. package/lib/test-utils/helpers/asyncHelpers.ts +11 -20
  362. package/lib/test-utils/helpers.ts +1 -5
  363. package/lib/test-utils/index.ts +0 -4
  364. package/lib/test-utils/mockFactories.ts +12 -18
  365. package/lib/test-utils/mocks.ts +4 -2
  366. package/package.json +1 -1
  367. package/scripts/build-meno-filter.ts +1 -4
  368. package/vite.config.ts +4 -4
  369. package/dist/chunks/chunk-2MHDV5BF.js.map +0 -7
  370. package/dist/chunks/chunk-AZQYF6KE.js.map +0 -7
  371. package/dist/chunks/chunk-GZHGVVW3.js.map +0 -7
  372. package/dist/chunks/chunk-H3GJ4H2U.js.map +0 -7
  373. package/dist/chunks/chunk-I7YIGZXT.js.map +0 -7
  374. package/dist/chunks/chunk-IGYR22T6.js.map +0 -7
  375. package/dist/chunks/chunk-JGP5A3Y5.js.map +0 -7
  376. package/dist/chunks/chunk-JGWFTO6P.js.map +0 -7
  377. package/dist/chunks/chunk-O3NAGJP4.js.map +0 -7
  378. package/dist/chunks/chunk-QB2LNO4W.js.map +0 -7
  379. package/dist/chunks/chunk-R6XHAFBF.js.map +0 -7
  380. package/dist/chunks/chunk-UB44F4Z2.js.map +0 -7
  381. package/dist/chunks/chunk-WQFG7PAH.js.map +0 -7
  382. package/dist/chunks/chunk-X754AHS5.js.map +0 -7
  383. package/dist/chunks/chunk-YBLHKYFF.js.map +0 -7
  384. package/dist/chunks/configService-R3OGU2UD.js +0 -13
  385. /package/dist/chunks/{configService-R3OGU2UD.js.map → configService-PRJZF7Y6.js.map} +0 -0
  386. /package/dist/chunks/{constants-STK2YBIW.js.map → constants-KIQEYMAM.js.map} +0 -0
  387. /package/dist/chunks/{fs-JGINUXGL.js.map → fs-ZI5JEU7V.js.map} +0 -0
package/build-static.ts CHANGED
@@ -4,37 +4,37 @@
4
4
  * CSP-compliant: Extracts JavaScript to external files
5
5
  */
6
6
 
7
- import { existsSync, readdirSync, mkdirSync, rmSync, statSync, copyFileSync, unlinkSync, writeFileSync } from "fs";
8
- import { writeFile, readFile } from "fs/promises";
9
- import { join } from "path";
10
- import type { BuildError, BuildErrorsData } from "./lib/server/ssr/buildErrorOverlay";
11
- import { createHash } from "crypto";
7
+ import { existsSync, readdirSync, mkdirSync, rmSync, statSync, copyFileSync, unlinkSync, writeFileSync } from 'fs';
8
+ import { writeFile, readFile } from 'fs/promises';
9
+ import { join } from 'path';
10
+ import type { BuildError, BuildErrorsData } from './lib/server/ssr/buildErrorOverlay';
11
+ import { createHash } from 'crypto';
12
12
  import { inspect, minifyJS as runtimeMinifyJS } from './lib/server/runtime';
13
13
  import {
14
14
  loadJSONFile,
15
15
  loadComponentDirectory,
16
16
  mapPageNameToPath,
17
17
  parseJSON,
18
- loadI18nConfig
19
- } from "./lib/server/jsonLoader";
20
- import { generateSSRHTML } from "./lib/server/ssrRenderer";
21
- import type { SSRHTMLResult } from "./lib/server/ssr/htmlGenerator";
22
- import { prepareClientData, type ClientDataCollection } from "./lib/server/ssr/clientDataInjector";
23
- import { clearJSValidationCache, getJSValidationErrors } from "./lib/server/ssr/jsCollector";
24
- import { projectPaths } from "./lib/server/projectContext";
25
- import { loadProjectConfig } from "./lib/shared/fontLoader";
26
- import { FileSystemCMSProvider } from "./lib/server/providers/fileSystemCMSProvider";
27
- import { CMSService } from "./lib/server/services/cmsService";
28
- import { isI18nValue, resolveI18nValue } from "./lib/shared/i18n";
29
- import type { ComponentDefinition, JSONPage, CMSSchema, CMSItem, I18nConfig, Experiment } from "./lib/shared/types";
30
- import { isItemDraftForLocale, isItemFullyPublished } from "./lib/shared/types";
31
- import type { SlugMap } from "./lib/shared/slugTranslator";
32
- import { buildItemUrl } from "./lib/shared/itemTemplateUtils";
33
- import { generateMiddleware, generateTrackFunction, generateResultsFunction } from "./lib/server/ab/generateFunctions";
34
- import { generateTrackingScript } from "./lib/server/ab/trackingScript";
35
- import { migrateTemplatesDirectory } from "./lib/server/migrateTemplates";
36
- import { extractLibraryOrigins, collectComponentLibraries, filterLibrariesByContext } from "./lib/shared/libraryLoader";
37
- import type { LibrariesConfig } from "./lib/shared/types/libraries";
18
+ loadI18nConfig,
19
+ } from './lib/server/jsonLoader';
20
+ import { generateSSRHTML } from './lib/server/ssrRenderer';
21
+ import type { SSRHTMLResult } from './lib/server/ssr/htmlGenerator';
22
+ import { prepareClientData, type ClientDataCollection } from './lib/server/ssr/clientDataInjector';
23
+ import { clearJSValidationCache, getJSValidationErrors } from './lib/server/ssr/jsCollector';
24
+ import { projectPaths } from './lib/server/projectContext';
25
+ import { loadProjectConfig } from './lib/shared/fontLoader';
26
+ import { FileSystemCMSProvider } from './lib/server/providers/fileSystemCMSProvider';
27
+ import { CMSService } from './lib/server/services/cmsService';
28
+ import { isI18nValue, resolveI18nValue } from './lib/shared/i18n';
29
+ import type { ComponentDefinition, JSONPage, CMSSchema, CMSItem, I18nConfig, Experiment } from './lib/shared/types';
30
+ import { isItemDraftForLocale, isItemFullyPublished } from './lib/shared/types';
31
+ import type { SlugMap } from './lib/shared/slugTranslator';
32
+ import { buildItemUrl } from './lib/shared/itemTemplateUtils';
33
+ import { generateMiddleware, generateTrackFunction, generateResultsFunction } from './lib/server/ab/generateFunctions';
34
+ import { generateTrackingScript } from './lib/server/ab/trackingScript';
35
+ import { migrateTemplatesDirectory } from './lib/server/migrateTemplates';
36
+ import { extractLibraryOrigins, collectComponentLibraries, filterLibrariesByContext } from './lib/shared/libraryLoader';
37
+ import type { LibrariesConfig } from './lib/shared/types/libraries';
38
38
 
39
39
  /**
40
40
  * Collect build errors for error overlay
@@ -157,6 +157,15 @@ function copyDirectory(src: string, dest: string): void {
157
157
  }
158
158
  }
159
159
 
160
+ /**
161
+ * Normalize a slug from meta.slugs to a bare slug (no leading/trailing slashes).
162
+ * Editors/importers sometimes store path-like slugs ("/", "/privacy") — without
163
+ * this, "/" produces a file literally named ".html" instead of "index.html".
164
+ * Mirrors the defensive strip in buildPageUrlForLocale (slugTranslator.ts).
165
+ */
166
+ function normalizeSlug(slug: string): string {
167
+ return slug.replace(/^\/+|\/+$/g, '');
168
+ }
160
169
 
161
170
  /**
162
171
  * Get locale-specific output path for a page with translated slug support
@@ -168,20 +177,20 @@ export function getLocalizedOutputPath(
168
177
  locale: string,
169
178
  defaultLocale: string,
170
179
  distDir: string,
171
- slugs?: Record<string, string>
180
+ slugs?: Record<string, string>,
172
181
  ): string {
173
182
  // Get translated slug for this locale, or fall back to default path
174
183
  let slug: string;
175
184
  if (slugs && slugs[locale]) {
176
- slug = slugs[locale];
177
- } else if (basePath === "/") {
178
- slug = "";
185
+ slug = normalizeSlug(slugs[locale]);
186
+ } else if (basePath === '/') {
187
+ slug = '';
179
188
  } else {
180
189
  slug = basePath.substring(1);
181
190
  }
182
191
 
183
192
  // Build filename from slug
184
- const fileName = slug === "" ? "index.html" : `${slug}.html`;
193
+ const fileName = slug === '' ? 'index.html' : `${slug}.html`;
185
194
 
186
195
  if (locale === defaultLocale) {
187
196
  return `${distDir}/${fileName}`;
@@ -196,22 +205,22 @@ export function getDisplayPath(
196
205
  basePath: string,
197
206
  locale: string,
198
207
  defaultLocale: string,
199
- slugs?: Record<string, string>
208
+ slugs?: Record<string, string>,
200
209
  ): string {
201
210
  // Get translated slug for this locale
202
211
  let slug: string;
203
212
  if (slugs && slugs[locale]) {
204
- slug = slugs[locale];
205
- } else if (basePath === "/") {
206
- slug = "";
213
+ slug = normalizeSlug(slugs[locale]);
214
+ } else if (basePath === '/') {
215
+ slug = '';
207
216
  } else {
208
217
  slug = basePath.substring(1);
209
218
  }
210
219
 
211
220
  if (locale === defaultLocale) {
212
- return slug === "" ? "/" : `/${slug}`;
221
+ return slug === '' ? '/' : `/${slug}`;
213
222
  }
214
- return slug === "" ? `/${locale}` : `/${locale}/${slug}`;
223
+ return slug === '' ? `/${locale}` : `/${locale}/${slug}`;
215
224
  }
216
225
 
217
226
  /**
@@ -233,9 +242,7 @@ export async function generateSitemap(urls: string[], siteUrl: string, distDir:
233
242
  // Sort URLs for deterministic output
234
243
  const sortedUrls = [...urls].sort();
235
244
 
236
- const urlEntries = sortedUrls
237
- .map(url => ` <url><loc>${siteUrl}${url}</loc></url>`)
238
- .join('\n');
245
+ const urlEntries = sortedUrls.map((url) => ` <url><loc>${siteUrl}${url}</loc></url>`).join('\n');
239
246
 
240
247
  const content = `<?xml version="1.0" encoding="UTF-8"?>
241
248
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
@@ -259,13 +266,7 @@ function cleanDist(distDir: string = projectPaths.dist()): void {
259
266
 
260
267
  for (const file of files) {
261
268
  // Keep fonts, images, icons, assets, and videos
262
- if (
263
- file === "fonts" ||
264
- file === "images" ||
265
- file === "icons" ||
266
- file === "assets" ||
267
- file === "videos"
268
- ) {
269
+ if (file === 'fonts' || file === 'images' || file === 'icons' || file === 'assets' || file === 'videos') {
269
270
  continue;
270
271
  }
271
272
 
@@ -306,7 +307,7 @@ export function buildCMSItemPath(
306
307
  item: CMSItem,
307
308
  slugField: string,
308
309
  locale: string,
309
- i18nConfig: I18nConfig
310
+ i18nConfig: I18nConfig,
310
311
  ): string {
311
312
  // Get slug from the schema-defined slugField, fall back to _slug or _id
312
313
  let slug = item[slugField] ?? item._slug ?? item._id;
@@ -325,7 +326,7 @@ export function buildCMSItemPath(
325
326
  */
326
327
  async function generateStaticDataFiles(
327
328
  staticCollections: Map<string, ClientDataCollection>,
328
- distDir: string
329
+ distDir: string,
329
330
  ): Promise<void> {
330
331
  if (staticCollections.size === 0) return;
331
332
 
@@ -355,7 +356,7 @@ async function buildCMSTemplates(
355
356
  generatedUrls: Set<string>,
356
357
  staticCollections: Map<string, ClientDataCollection>,
357
358
  siteUrl?: string,
358
- abTrackingScript?: string | null
359
+ abTrackingScript?: string | null,
359
360
  ): Promise<{ success: number; errors: number }> {
360
361
  let successCount = 0;
361
362
  let errorCount = 0;
@@ -364,7 +365,7 @@ async function buildCMSTemplates(
364
365
  return { success: 0, errors: 0 };
365
366
  }
366
367
 
367
- const templateFiles = readdirSync(templatesDir).filter(f => f.endsWith('.json'));
368
+ const templateFiles = readdirSync(templatesDir).filter((f) => f.endsWith('.json'));
368
369
 
369
370
  if (templateFiles.length === 0) {
370
371
  return { success: 0, errors: 0 };
@@ -408,17 +409,21 @@ async function buildCMSTemplates(
408
409
  // Filter out fully-draft items from client data (client data is locale-agnostic)
409
410
  let clientDataCollections: Map<string, ClientDataCollection> | undefined;
410
411
  if (cmsSchema.clientData?.enabled) {
411
- const publishedItems = items.filter(item => isItemFullyPublished(item));
412
+ const publishedItems = items.filter((item) => isItemFullyPublished(item));
412
413
  const clientData = prepareClientData(cmsSchema.id, publishedItems, cmsSchema.clientData);
413
414
  if (clientData) {
414
415
  if (clientData.strategy === 'inline') {
415
416
  // Inline data embedded in HTML
416
417
  clientDataCollections = new Map([[cmsSchema.id, clientData]]);
417
- console.log(` 📦 Client data (inline): ${clientData.items.length} items (${clientData.config.fields?.length || 'all'} fields)`);
418
+ console.log(
419
+ ` 📦 Client data (inline): ${clientData.items.length} items (${clientData.config.fields?.length || 'all'} fields)`,
420
+ );
418
421
  } else if (clientData.strategy === 'static') {
419
422
  // Static data written to separate file
420
423
  staticCollections.set(cmsSchema.id, clientData);
421
- console.log(` 📦 Client data (static): ${clientData.items.length} items → /data/${cmsSchema.id}/index.json`);
424
+ console.log(
425
+ ` 📦 Client data (static): ${clientData.items.length} items → /data/${cmsSchema.id}/index.json`,
426
+ );
422
427
  }
423
428
  }
424
429
  }
@@ -434,14 +439,14 @@ async function buildCMSTemplates(
434
439
  continue;
435
440
  }
436
441
 
437
- const baseUrl = siteUrl || "";
442
+ const baseUrl = siteUrl || '';
438
443
  const itemPath = buildCMSItemPath(cmsSchema.urlPattern, item, cmsSchema.slugField, locale, i18nConfig);
439
444
 
440
445
  // Create CMS item with computed _url for {{cms._url}} template access
441
446
  const itemWithUrl: CMSItem = { ...item, _url: itemPath };
442
447
 
443
448
  // Generate HTML with JS returned separately (CSP-compliant)
444
- const result = await generateSSRHTML({
449
+ const result = (await generateSSRHTML({
445
450
  pageData,
446
451
  globalComponents,
447
452
  pagePath: itemPath,
@@ -456,7 +461,7 @@ async function buildCMSTemplates(
456
461
  pageCustomCode: pageData.meta?.customCode,
457
462
  clientDataCollections,
458
463
  isProductionBuild: true,
459
- }) as SSRHTMLResult;
464
+ })) as SSRHTMLResult;
460
465
 
461
466
  // If there's JavaScript, write to external file and update HTML
462
467
  let finalHtml = result.html;
@@ -470,9 +475,8 @@ async function buildCMSTemplates(
470
475
  finalHtml = injectTrackingScript(finalHtml, abTrackingScript);
471
476
  }
472
477
 
473
- const outputPath = locale === i18nConfig.defaultLocale
474
- ? `${distDir}${itemPath}.html`
475
- : `${distDir}/${locale}${itemPath}.html`;
478
+ const outputPath =
479
+ locale === i18nConfig.defaultLocale ? `${distDir}${itemPath}.html` : `${distDir}/${locale}${itemPath}.html`;
476
480
 
477
481
  const outputDir = outputPath.substring(0, outputPath.lastIndexOf('/'));
478
482
  if (outputDir && !existsSync(outputDir)) {
@@ -498,16 +502,14 @@ async function buildCMSTemplates(
498
502
  }
499
503
  // Check for cause chain
500
504
  else if (error.cause) {
501
- const causeMsg = error.cause instanceof Error
502
- ? (error.cause.stack || error.cause.message)
503
- : String(error.cause);
505
+ const causeMsg =
506
+ error.cause instanceof Error ? error.cause.stack || error.cause.message : String(error.cause);
504
507
  errorMessage = `${error.stack || error.message}\n\nCaused by:\n${causeMsg}`;
505
508
  }
506
509
  // Bun's BuildMessage has logs array
507
510
  else if ('logs' in error && Array.isArray(error.logs)) {
508
511
  errorMessage = error.logs.map(formatBunLog).join('\n\n');
509
- }
510
- else {
512
+ } else {
511
513
  errorMessage = error.stack || error.message;
512
514
  }
513
515
  } else if (typeof error === 'object' && error !== null) {
@@ -555,7 +557,7 @@ async function loadRunningExperiments(): Promise<Experiment[]> {
555
557
  const content = await readFile(experimentsPath, 'utf-8');
556
558
  const data = JSON.parse(content);
557
559
  const experiments: Experiment[] = data.experiments || [];
558
- return experiments.filter(e => e.status === 'running');
560
+ return experiments.filter((e) => e.status === 'running');
559
561
  } catch {
560
562
  return [];
561
563
  }
@@ -601,14 +603,14 @@ async function generateABFunctions(experiments: Experiment[], distDir: string):
601
603
  * Main build function
602
604
  */
603
605
  export async function buildStaticPages(outDir?: string): Promise<void> {
604
- console.log("🏗️ Building static HTML files...\n");
606
+ console.log('🏗️ Building static HTML files...\n');
605
607
 
606
608
  // Clear previous build errors and JS validation cache
607
609
  buildErrors.length = 0;
608
610
  clearJSValidationCache();
609
611
 
610
612
  // Reset configService to ensure it loads from the correct project directory
611
- const { configService } = await import("./lib/server/services/configService");
613
+ const { configService } = await import('./lib/server/services/configService');
612
614
  configService.reset();
613
615
 
614
616
  // Load project config first
@@ -629,7 +631,9 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
629
631
 
630
632
  // Load i18n config for multi-locale build
631
633
  const i18nConfig = await loadI18nConfig();
632
- console.log(`🌐 Locales: ${i18nConfig.locales.map(l => l.code).join(", ")} (default: ${i18nConfig.defaultLocale})\n`);
634
+ console.log(
635
+ `🌐 Locales: ${i18nConfig.locales.map((l) => l.code).join(', ')} (default: ${i18nConfig.defaultLocale})\n`,
636
+ );
633
637
 
634
638
  // Auto-migrate pages/templates/ → templates/ if needed
635
639
  await migrateTemplatesDirectory();
@@ -646,42 +650,42 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
646
650
  jsFileCache.clear();
647
651
 
648
652
  // Copy fonts, images, icons, and functions directories to dist
649
- console.log("📦 Copying assets...");
653
+ console.log('📦 Copying assets...');
650
654
 
651
655
  // Delete old _errors.json if it exists (start fresh)
652
656
  const errorsPath = join(distDir, '_errors.json');
653
657
  if (existsSync(errorsPath)) {
654
658
  unlinkSync(errorsPath);
655
659
  }
656
- copyDirectory(projectPaths.fonts(), join(distDir, "fonts"));
657
- copyDirectory(projectPaths.images(), join(distDir, "images"));
658
- copyDirectory(projectPaths.icons(), join(distDir, "icons"));
659
- copyDirectory(projectPaths.assets(), join(distDir, "assets"));
660
- copyDirectory(projectPaths.videos(), join(distDir, "videos"));
660
+ copyDirectory(projectPaths.fonts(), join(distDir, 'fonts'));
661
+ copyDirectory(projectPaths.images(), join(distDir, 'images'));
662
+ copyDirectory(projectPaths.icons(), join(distDir, 'icons'));
663
+ copyDirectory(projectPaths.assets(), join(distDir, 'assets'));
664
+ copyDirectory(projectPaths.videos(), join(distDir, 'videos'));
661
665
 
662
666
  // Copy libraries folder (downloaded external JS/CSS files)
663
- const librariesDir = join(projectPaths.project, "libraries");
667
+ const librariesDir = join(projectPaths.project, 'libraries');
664
668
  if (existsSync(librariesDir)) {
665
- copyDirectory(librariesDir, join(distDir, "libraries"));
669
+ copyDirectory(librariesDir, join(distDir, 'libraries'));
666
670
  }
667
671
 
668
672
  // Copy functions folder for Cloudflare Pages
669
673
  const functionsDir = projectPaths.functions();
670
674
  if (existsSync(functionsDir)) {
671
- copyDirectory(functionsDir, join(distDir, "functions"));
675
+ copyDirectory(functionsDir, join(distDir, 'functions'));
672
676
  }
673
677
 
674
678
  // Copy user-created root files for static hosting
675
679
  const hostingFiles: string[] = [];
676
680
  const rootFilesToCopy = [
677
- '_headers', // Netlify/Cloudflare headers
678
- '_redirects', // Netlify/Cloudflare redirects
679
- 'llms.txt', // LLM context
680
- 'humans.txt', // Team credits
681
- 'ads.txt', // Ad verification
682
- 'security.txt', // Security contact
683
- 'CNAME', // GitHub Pages domain
684
- 'manifest.json', // PWA manifest
681
+ '_headers', // Netlify/Cloudflare headers
682
+ '_redirects', // Netlify/Cloudflare redirects
683
+ 'llms.txt', // LLM context
684
+ 'humans.txt', // Team credits
685
+ 'ads.txt', // Ad verification
686
+ 'security.txt', // Security contact
687
+ 'CNAME', // GitHub Pages domain
688
+ 'manifest.json', // PWA manifest
685
689
  'site.webmanifest', // PWA manifest (alt)
686
690
  ];
687
691
 
@@ -725,7 +729,7 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
725
729
  // Load all pages
726
730
  const pagesDir = projectPaths.pages();
727
731
  if (!existsSync(pagesDir)) {
728
- console.error("❌ Pages directory not found!");
732
+ console.error('❌ Pages directory not found!');
729
733
  process.exit(1);
730
734
  }
731
735
 
@@ -742,9 +746,9 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
742
746
  }
743
747
  }
744
748
  scanPagesDir(pagesDir, '');
745
-
749
+
746
750
  if (pageFiles.length === 0) {
747
- console.warn("⚠️ No pages found in ./pages directory");
751
+ console.warn('⚠️ No pages found in ./pages directory');
748
752
  return;
749
753
  }
750
754
 
@@ -754,7 +758,7 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
754
758
  const slugMappings: SlugMap[] = [];
755
759
  const allPageLibraries: LibrariesConfig[] = [];
756
760
  for (const file of pageFiles) {
757
- const pageName = file.replace(".json", "");
761
+ const pageName = file.replace('.json', '');
758
762
  const basePath = mapPageNameToPath(pageName);
759
763
  const pageContent = await loadJSONFile(join(pagesDir, file));
760
764
  if (pageContent) {
@@ -767,7 +771,9 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
767
771
  if (pageData.meta?.libraries) {
768
772
  allPageLibraries.push(pageData.meta.libraries as LibrariesConfig);
769
773
  }
770
- } catch { /* ignore parse errors in first pass */ }
774
+ } catch {
775
+ /* ignore parse errors in first pass */
776
+ }
771
777
  }
772
778
  }
773
779
 
@@ -786,12 +792,12 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
786
792
  const allJs = [
787
793
  ...(globalLibraries.js || []),
788
794
  ...(componentLibraries.js || []),
789
- ...allPageLibraries.flatMap(p => p.js || []),
795
+ ...allPageLibraries.flatMap((p) => p.js || []),
790
796
  ];
791
797
  const allCss = [
792
798
  ...(globalLibraries.css || []),
793
799
  ...(componentLibraries.css || []),
794
- ...allPageLibraries.flatMap(p => p.css || []),
800
+ ...allPageLibraries.flatMap((p) => p.css || []),
795
801
  ];
796
802
  const allLibs: LibrariesConfig = { js: allJs, css: allCss };
797
803
 
@@ -801,14 +807,8 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
801
807
  // Extract CDN origins from all library URLs
802
808
  const { scriptOrigins, styleOrigins } = extractLibraryOrigins(buildLibs);
803
809
 
804
- const extraScripts = [
805
- ...(cspConfig.scriptSrc || []),
806
- ...Array.from(scriptOrigins),
807
- ].join(' ');
808
- const extraStyles = [
809
- ...(cspConfig.styleSrc || []),
810
- ...Array.from(styleOrigins),
811
- ].join(' ');
810
+ const extraScripts = [...(cspConfig.scriptSrc || []), ...Array.from(scriptOrigins)].join(' ');
811
+ const extraStyles = [...(cspConfig.styleSrc || []), ...Array.from(styleOrigins)].join(' ');
812
812
  const extraConnect = cspConfig.connectSrc?.join(' ') || '';
813
813
  const extraFrames = cspConfig.frameSrc?.join(' ') || '';
814
814
  const extraFonts = cspConfig.fontSrc?.join(' ') || '';
@@ -829,12 +829,14 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
829
829
  `connect-src 'self' https://vimeo.com https://*.vimeocdn.com ${extraConnect}`.trim(),
830
830
  `frame-src https://player.vimeo.com https://vimeo.com https://www.youtube.com https://www.youtube-nocookie.com ${extraFrames}`.trim(),
831
831
  `font-src 'self' data: ${extraFonts}`.trim(),
832
- "media-src 'self' https: blob:"
832
+ "media-src 'self' https: blob:",
833
833
  ].join('; ');
834
834
 
835
835
  const headersContent = `/*\n Content-Security-Policy: ${cspDirectives}\n`;
836
836
  writeFileSync(join(distDir, '_headers'), headersContent);
837
- console.log(`✅ Generated _headers with CSP (auto-included ${scriptOrigins.size + styleOrigins.size} library origin(s))\n`);
837
+ console.log(
838
+ `✅ Generated _headers with CSP (auto-included ${scriptOrigins.size + styleOrigins.size} library origin(s))\n`,
839
+ );
838
840
  }
839
841
  }
840
842
 
@@ -843,7 +845,7 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
843
845
 
844
846
  // Build each page for each locale
845
847
  for (const file of pageFiles) {
846
- const pageName = file.replace(".json", "");
848
+ const pageName = file.replace('.json', '');
847
849
  const basePath = mapPageNameToPath(pageName);
848
850
  const pageContent = await loadJSONFile(join(pagesDir, file));
849
851
 
@@ -869,13 +871,13 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
869
871
  // Generate HTML for each locale
870
872
  for (const localeConfig of i18nConfig.locales) {
871
873
  const locale = localeConfig.code;
872
- const baseUrl = siteUrl || "";
874
+ const baseUrl = siteUrl || '';
873
875
 
874
876
  // Build the URL path that will be used for this locale
875
877
  const urlPath = getDisplayPath(basePath, locale, i18nConfig.defaultLocale, slugs);
876
878
 
877
879
  // Generate HTML with JS returned separately (CSP-compliant)
878
- const result = await generateSSRHTML({
880
+ const result = (await generateSSRHTML({
879
881
  pageData,
880
882
  globalComponents,
881
883
  pagePath: urlPath,
@@ -888,7 +890,7 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
888
890
  pageLibraries: pageData.meta?.libraries,
889
891
  pageCustomCode: pageData.meta?.customCode,
890
892
  isProductionBuild: true,
891
- }) as SSRHTMLResult;
893
+ })) as SSRHTMLResult;
892
894
 
893
895
  // If there's JavaScript, write to external file and update HTML
894
896
  let finalHtml = result.html;
@@ -907,7 +909,7 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
907
909
  const outputPath = getLocalizedOutputPath(basePath, locale, i18nConfig.defaultLocale, distDir, slugs);
908
910
 
909
911
  // Ensure directory exists
910
- const outputDir = outputPath.substring(0, outputPath.lastIndexOf("/"));
912
+ const outputDir = outputPath.substring(0, outputPath.lastIndexOf('/'));
911
913
  if (outputDir && !existsSync(outputDir)) {
912
914
  mkdirSync(outputDir, { recursive: true });
913
915
  }
@@ -917,13 +919,12 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
917
919
  console.log('[DEBUG] Last 500 chars of HTML:', finalHtml.slice(-500));
918
920
  }
919
921
 
920
- await writeFile(outputPath, finalHtml, "utf-8");
922
+ await writeFile(outputPath, finalHtml, 'utf-8');
921
923
 
922
924
  generatedUrls.add(urlPath);
923
925
  console.log(`✅ Built: ${urlPath} → ${outputPath}`);
924
926
  successCount++;
925
927
  }
926
-
927
928
  } catch (error: any) {
928
929
  // Capture full error with as much detail as possible
929
930
  let errorMessage: string;
@@ -935,16 +936,14 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
935
936
  }
936
937
  // Check for cause chain
937
938
  else if (error.cause) {
938
- const causeMsg = error.cause instanceof Error
939
- ? (error.cause.stack || error.cause.message)
940
- : String(error.cause);
939
+ const causeMsg =
940
+ error.cause instanceof Error ? error.cause.stack || error.cause.message : String(error.cause);
941
941
  errorMessage = `${error.stack || error.message}\n\nCaused by:\n${causeMsg}`;
942
942
  }
943
943
  // Bun's BuildMessage has logs array
944
944
  else if ('logs' in error && Array.isArray(error.logs)) {
945
945
  errorMessage = error.logs.map(formatBunLog).join('\n\n');
946
- }
947
- else {
946
+ } else {
948
947
  errorMessage = error.stack || error.message;
949
948
  }
950
949
  } else if (typeof error === 'object' && error !== null) {
@@ -991,7 +990,7 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
991
990
  generatedUrls,
992
991
  staticCollections,
993
992
  siteUrl,
994
- trackingScript
993
+ trackingScript,
995
994
  );
996
995
  successCount += cmsResult.success;
997
996
  errorCount += cmsResult.errors;
@@ -1014,7 +1013,7 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
1014
1013
  console.warn(`\n⚠️ Skipping SEO files: siteUrl not configured in project.config.json`);
1015
1014
  }
1016
1015
 
1017
- console.log("\n" + "=".repeat(50));
1016
+ console.log('\n' + '='.repeat(50));
1018
1017
  console.log(`✨ Build complete!`);
1019
1018
  console.log(` ✅ Success: ${successCount}`);
1020
1019
  if (errorCount > 0) {
@@ -1053,7 +1052,7 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
1053
1052
  if (buildErrors.length > 0) {
1054
1053
  // Deduplicate errors by message (same error may occur on multiple pages)
1055
1054
  const seenMessages = new Set<string>();
1056
- const uniqueErrors = buildErrors.filter(err => {
1055
+ const uniqueErrors = buildErrors.filter((err) => {
1057
1056
  if (seenMessages.has(err.message)) return false;
1058
1057
  seenMessages.add(err.message);
1059
1058
  return true;
@@ -1064,11 +1063,10 @@ export async function buildStaticPages(outDir?: string): Promise<void> {
1064
1063
  timestamp: Date.now(),
1065
1064
  };
1066
1065
  await writeFile(errorsPath, JSON.stringify(errorsData, null, 2), 'utf-8');
1067
- const countMsg = uniqueErrors.length === buildErrors.length
1068
- ? `${uniqueErrors.length} error${uniqueErrors.length === 1 ? '' : 's'}`
1069
- : `${uniqueErrors.length} unique error${uniqueErrors.length === 1 ? '' : 's'} (affected ${buildErrors.length} files)`;
1066
+ const countMsg =
1067
+ uniqueErrors.length === buildErrors.length
1068
+ ? `${uniqueErrors.length} error${uniqueErrors.length === 1 ? '' : 's'}`
1069
+ : `${uniqueErrors.length} unique error${uniqueErrors.length === 1 ? '' : 's'} (affected ${buildErrors.length} files)`;
1070
1070
  console.log(`\n⚠️ Build errors written to dist/_errors.json (${countMsg})`);
1071
1071
  }
1072
1072
  }
1073
-
1074
-