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
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  configService
3
- } from "./chunk-2MHDV5BF.js";
3
+ } from "./chunk-7E4IF5L7.js";
4
4
  import {
5
5
  projectPaths,
6
6
  resolveProjectPath,
7
7
  validateJS
8
- } from "./chunk-I7YIGZXT.js";
8
+ } from "./chunk-JNO3CNLJ.js";
9
9
  import {
10
10
  fileExists,
11
11
  readJsonFile,
12
12
  readTextFile,
13
13
  writeFile
14
- } from "./chunk-WQFG7PAH.js";
14
+ } from "./chunk-FZITJSSS.js";
15
15
  import {
16
16
  CMS_DRAFT_SUFFIX,
17
17
  buildSlugIndex,
@@ -27,7 +27,7 @@ import {
27
27
  mergeLibraries,
28
28
  resolvePaletteColor,
29
29
  translatePath
30
- } from "./chunk-X754AHS5.js";
30
+ } from "./chunk-5ETZFREW.js";
31
31
  import {
32
32
  extractAttributesFromNode,
33
33
  inlineSvgStyleRules,
@@ -36,7 +36,7 @@ import {
36
36
  processStructure,
37
37
  resolveHtmlMapping,
38
38
  skipEmptyTemplateAttributes
39
- } from "./chunk-O3NAGJP4.js";
39
+ } from "./chunk-AE3QK5QW.js";
40
40
  import {
41
41
  DEFAULT_PREFETCH_CONFIG,
42
42
  SSRRegistry,
@@ -78,32 +78,35 @@ import {
78
78
  validateCMSDraftItem,
79
79
  validateCMSItem,
80
80
  validateComponentDefinition
81
- } from "./chunk-JGWFTO6P.js";
81
+ } from "./chunk-7HWQUVTU.js";
82
82
  import {
83
83
  DEFAULT_BREAKPOINTS,
84
84
  DEFAULT_FLUID_RANGE,
85
- DEFAULT_I18N_CONFIG,
86
85
  DEFAULT_SITE_MARGIN,
87
86
  buildFluidPropertyValue,
88
- buildLocalizedPath,
89
87
  buildSiteMarginClamp,
90
- extractLocaleFromPath,
91
88
  getSmallestBreakpointName,
92
- isI18nValue,
93
- migrateI18nConfig,
89
+ logRuntimeError,
94
90
  normalizeBreakpointConfig,
95
- resolveI18nValue,
96
91
  scalePropertyValue
97
- } from "./chunk-AZQYF6KE.js";
92
+ } from "./chunk-I2WEGYA7.js";
93
+ import {
94
+ DEFAULT_I18N_CONFIG,
95
+ buildLocalizedPath,
96
+ extractLocaleFromPath,
97
+ isI18nValue,
98
+ migrateI18nConfig,
99
+ resolveI18nValue
100
+ } from "./chunk-3XER4E5W.js";
98
101
  import {
99
102
  isTiptapDocument,
100
103
  tiptapToHtml
101
- } from "./chunk-UB44F4Z2.js";
104
+ } from "./chunk-NVRBTSQG.js";
102
105
  import {
103
106
  NODE_TYPE,
104
107
  RAW_HTML_PREFIX,
105
108
  init_constants
106
- } from "./chunk-YBLHKYFF.js";
109
+ } from "./chunk-HIZMY3EP.js";
107
110
  import {
108
111
  __require
109
112
  } from "./chunk-KSBZ2L7C.js";
@@ -179,7 +182,7 @@ function attemptJsonRepair(content) {
179
182
  const nextLine = i + 1 < lines.length ? lines[i + 1] : null;
180
183
  if (nextLine !== null) {
181
184
  const nextTrimmed = nextLine.trimStart();
182
- const needsComma = /["\d\w\]}\-]$/.test(trimmed) && !trimmed.endsWith(",") && !trimmed.endsWith("{") && !trimmed.endsWith("[") && !trimmed.endsWith(":") && (nextTrimmed.startsWith('"') || nextTrimmed.startsWith("{") || nextTrimmed.startsWith("[") || /^\d/.test(nextTrimmed) || nextTrimmed === "true" || nextTrimmed === "false" || nextTrimmed === "null");
185
+ const needsComma = /["\d\w\]}-]$/.test(trimmed) && !trimmed.endsWith(",") && !trimmed.endsWith("{") && !trimmed.endsWith("[") && !trimmed.endsWith(":") && (nextTrimmed.startsWith('"') || nextTrimmed.startsWith("{") || nextTrimmed.startsWith("[") || /^\d/.test(nextTrimmed) || nextTrimmed === "true" || nextTrimmed === "false" || nextTrimmed === "null");
183
186
  if (needsComma) {
184
187
  fixed += trimmed + ",\n";
185
188
  if (repairLine === 0) repairLine = i + 1;
@@ -224,6 +227,7 @@ async function loadJSONFile(filePath) {
224
227
  }
225
228
  return null;
226
229
  } catch (error) {
230
+ logRuntimeError("jsonLoader.loadJSONFile", error, { filePath });
227
231
  return null;
228
232
  }
229
233
  }
@@ -237,6 +241,7 @@ async function loadFileAsText(filePath) {
237
241
  }
238
242
  return null;
239
243
  } catch (error) {
244
+ logRuntimeError("jsonLoader.loadFileAsText", error, { filePath });
240
245
  return null;
241
246
  }
242
247
  }
@@ -275,10 +280,7 @@ async function loadSingleComponent(filePath, componentName, category) {
275
280
  const dirPath = filePath.substring(0, filePath.lastIndexOf("/"));
276
281
  const jsFilePath = `${dirPath}/${componentName}.js`;
277
282
  const cssFilePath = `${dirPath}/${componentName}.css`;
278
- const [jsContent, cssContent] = await Promise.all([
279
- loadFileAsText(jsFilePath),
280
- loadFileAsText(cssFilePath)
281
- ]);
283
+ const [jsContent, cssContent] = await Promise.all([loadFileAsText(jsFilePath), loadFileAsText(cssFilePath)]);
282
284
  if (!componentDef.component) {
283
285
  componentDef.component = {};
284
286
  }
@@ -297,6 +299,7 @@ async function loadSingleComponent(filePath, componentName, category) {
297
299
  }
298
300
  return { component: componentDef, warning };
299
301
  } catch (error) {
302
+ logRuntimeError("jsonLoader.loadSingleComponent", error, { filePath, componentName });
300
303
  return { component: null };
301
304
  }
302
305
  }
@@ -378,6 +381,7 @@ async function loadBreakpointConfig() {
378
381
  }
379
382
  }
380
383
  } catch (error) {
384
+ logRuntimeError("jsonLoader.loadBreakpointConfig", error, { filePath: projectPaths.config() });
381
385
  }
382
386
  return { ...DEFAULT_BREAKPOINTS };
383
387
  }
@@ -389,6 +393,7 @@ async function loadI18nConfig() {
389
393
  return migrateI18nConfig(config.i18n);
390
394
  }
391
395
  } catch (error) {
396
+ logRuntimeError("jsonLoader.loadI18nConfig", error, { filePath: projectPaths.config() });
392
397
  }
393
398
  return { ...DEFAULT_I18N_CONFIG };
394
399
  }
@@ -402,6 +407,7 @@ async function loadIconsConfig() {
402
407
  }
403
408
  }
404
409
  } catch (error) {
410
+ logRuntimeError("jsonLoader.loadIconsConfig", error, { filePath: projectPaths.config() });
405
411
  }
406
412
  return {};
407
413
  }
@@ -418,6 +424,7 @@ async function loadPrefetchConfig() {
418
424
  }
419
425
  }
420
426
  } catch (error) {
427
+ logRuntimeError("jsonLoader.loadPrefetchConfig", error, { filePath: projectPaths.config() });
421
428
  }
422
429
  return { ...DEFAULT_PREFETCH_CONFIG };
423
430
  }
@@ -497,44 +504,44 @@ var ColorService = class extends CachedConfigLoader {
497
504
  dark: {
498
505
  label: "Dark",
499
506
  colors: {
500
- "primary": "#007acc",
507
+ primary: "#007acc",
501
508
  "primary-light": "#0099ff",
502
509
  "primary-dark": "#005a99",
503
- "secondary": "#6c757d",
504
- "success": "#28a745",
505
- "warning": "#ffc107",
506
- "danger": "#dc3545",
507
- "error": "#d32f2f",
508
- "info": "#17a2b8",
509
- "light": "#f8f9fa",
510
- "dark": "#343a40",
511
- "text": "#cccccc",
510
+ secondary: "#6c757d",
511
+ success: "#28a745",
512
+ warning: "#ffc107",
513
+ danger: "#dc3545",
514
+ error: "#d32f2f",
515
+ info: "#17a2b8",
516
+ light: "#f8f9fa",
517
+ dark: "#343a40",
518
+ text: "#cccccc",
512
519
  "text-dark": "#1e1e1e",
513
- "background": "#1e1e1e",
520
+ background: "#1e1e1e",
514
521
  "background-light": "#252526",
515
- "border": "#444444",
522
+ border: "#444444",
516
523
  "border-light": "#d0d0d0"
517
524
  }
518
525
  },
519
526
  light: {
520
527
  label: "Light",
521
528
  colors: {
522
- "primary": "#0066ff",
529
+ primary: "#0066ff",
523
530
  "primary-light": "#3385ff",
524
531
  "primary-dark": "#0052cc",
525
- "secondary": "#888888",
526
- "success": "#22c55e",
527
- "warning": "#f59e0b",
528
- "danger": "#ef4444",
529
- "error": "#dc2626",
530
- "info": "#06b6d4",
531
- "light": "#f8f9fa",
532
- "dark": "#1f2937",
533
- "text": "#1f2937",
532
+ secondary: "#888888",
533
+ success: "#22c55e",
534
+ warning: "#f59e0b",
535
+ danger: "#ef4444",
536
+ error: "#dc2626",
537
+ info: "#06b6d4",
538
+ light: "#f8f9fa",
539
+ dark: "#1f2937",
540
+ text: "#1f2937",
534
541
  "text-dark": "#ffffff",
535
- "background": "#ffffff",
542
+ background: "#ffffff",
536
543
  "background-light": "#f3f4f6",
537
- "border": "#d1d5db",
544
+ border: "#d1d5db",
538
545
  "border-light": "#e5e7eb"
539
546
  }
540
547
  }
@@ -551,8 +558,8 @@ var ColorService = class extends CachedConfigLoader {
551
558
  default: {
552
559
  label: "Default",
553
560
  colors: {
554
- "background": "#1e1e1e",
555
- "text": "#cccccc"
561
+ background: "#1e1e1e",
562
+ text: "#cccccc"
556
563
  }
557
564
  }
558
565
  }
@@ -573,7 +580,12 @@ var ColorService = class extends CachedConfigLoader {
573
580
  if (data && typeof data === "object" && "themes" in data && "default" in data) {
574
581
  return { status: "valid", config: data, filePath };
575
582
  }
576
- return { status: "invalid", config: this.getMinimalConfig(), error: 'Invalid structure: missing "themes" or "default" property', filePath };
583
+ return {
584
+ status: "invalid",
585
+ config: this.getMinimalConfig(),
586
+ error: 'Invalid structure: missing "themes" or "default" property',
587
+ filePath
588
+ };
577
589
  } catch (error) {
578
590
  return {
579
591
  status: "invalid",
@@ -710,7 +722,12 @@ var VariableService = class extends CachedConfigLoader {
710
722
  if (data && typeof data === "object" && "variables" in data && Array.isArray(data.variables)) {
711
723
  return { status: "valid", config: this.migrateConfig(data), filePath };
712
724
  }
713
- return { status: "invalid", config: this.getDefaultConfig(), error: 'Invalid structure: missing "variables" array', filePath };
725
+ return {
726
+ status: "invalid",
727
+ config: this.getDefaultConfig(),
728
+ error: 'Invalid structure: missing "variables" array',
729
+ filePath
730
+ };
714
731
  } catch (error) {
715
732
  return {
716
733
  status: "invalid",
@@ -978,9 +995,7 @@ var CMSService = class {
978
995
  const slugValue = item[schemaInfo.schema.slugField];
979
996
  if (typeof slugValue === "string") {
980
997
  if (options?.excludeDrafts && defaultLocale && isItemDraftForLocale(item, defaultLocale)) continue;
981
- urls.push(
982
- schemaInfo.schema.urlPattern.replace("{{slug}}", slugValue)
983
- );
998
+ urls.push(schemaInfo.schema.urlPattern.replace("{{slug}}", slugValue));
984
999
  } else if (isI18nValue(slugValue) && locales) {
985
1000
  for (const locale of locales) {
986
1001
  if (options?.excludeDrafts && isItemDraftForLocale(item, locale)) continue;
@@ -997,9 +1012,7 @@ var CMSService = class {
997
1012
  } else if (isI18nValue(slugValue)) {
998
1013
  for (const key of Object.keys(slugValue)) {
999
1014
  if (key !== "_i18n" && typeof slugValue[key] === "string") {
1000
- urls.push(
1001
- schemaInfo.schema.urlPattern.replace("{{slug}}", slugValue[key])
1002
- );
1015
+ urls.push(schemaInfo.schema.urlPattern.replace("{{slug}}", slugValue[key]));
1003
1016
  break;
1004
1017
  }
1005
1018
  }
@@ -1154,14 +1167,10 @@ var CMSService = class {
1154
1167
  */
1155
1168
  applyFilters(items, filter) {
1156
1169
  if (!Array.isArray(filter) && !this.isFilterCondition(filter)) {
1157
- return items.filter(
1158
- (item) => Object.entries(filter).every(([key, value]) => item[key] === value)
1159
- );
1170
+ return items.filter((item) => Object.entries(filter).every(([key, value]) => item[key] === value));
1160
1171
  }
1161
1172
  const conditions = Array.isArray(filter) ? filter : [filter];
1162
- return items.filter(
1163
- (item) => conditions.every((cond) => this.matchCondition(item, cond))
1164
- );
1173
+ return items.filter((item) => conditions.every((cond) => this.matchCondition(item, cond)));
1165
1174
  }
1166
1175
  /**
1167
1176
  * Check if object is a CMSFilterCondition
@@ -1211,9 +1220,7 @@ var CMSService = class {
1211
1220
  }
1212
1221
  const allItems = await this.getCachedItems(collection);
1213
1222
  const itemMap = new Map(allItems.map((item) => [item._id, item]));
1214
- const filenameMap = new Map(
1215
- allItems.filter((item) => item._filename).map((item) => [item._filename, item])
1216
- );
1223
+ const filenameMap = new Map(allItems.filter((item) => item._filename).map((item) => [item._filename, item]));
1217
1224
  return ids.filter(Boolean).map((id) => itemMap.get(id) || filenameMap.get(id)).filter((item) => item !== void 0);
1218
1225
  }
1219
1226
  /**
@@ -1260,7 +1267,9 @@ var CMSService = class {
1260
1267
  const allSchemas = this.getAllSchemas();
1261
1268
  for (const [collectionId, schemaInfo] of allSchemas) {
1262
1269
  const { schema } = schemaInfo;
1263
- const refFields = Object.entries(schema.fields).filter(([_, def]) => def.type === "reference" && def.collection === targetCollection);
1270
+ const refFields = Object.entries(schema.fields).filter(
1271
+ ([_, def]) => def.type === "reference" && def.collection === targetCollection
1272
+ );
1264
1273
  if (refFields.length === 0) continue;
1265
1274
  const items = await this.getCachedItems(collectionId);
1266
1275
  for (const item of items) {
@@ -1384,13 +1393,7 @@ function generateVariablesCSS(config, breakpoints, responsiveScales) {
1384
1393
  const categoryScales = responsiveScales?.[v.type];
1385
1394
  const scale = categoryScales?.[smallestBp];
1386
1395
  if (scale != null && scale !== 1) {
1387
- const fluid = buildFluidPropertyValue(
1388
- v.value,
1389
- scale,
1390
- fluidRange.min,
1391
- fluidRange.max,
1392
- fluidBaseRef
1393
- );
1396
+ const fluid = buildFluidPropertyValue(v.value, scale, fluidRange.min, fluidRange.max, fluidBaseRef);
1394
1397
  if (fluid) return ` ${v.cssVar}: ${fluid};`;
1395
1398
  }
1396
1399
  }
@@ -1430,13 +1433,11 @@ ${baseVars.join("\n")}
1430
1433
  }
1431
1434
  }
1432
1435
  if (scaledVars.length > 0) {
1433
- cssBlocks.push(
1434
- `@media (max-width: ${bpEntry.breakpoint}px) {
1436
+ cssBlocks.push(`@media (max-width: ${bpEntry.breakpoint}px) {
1435
1437
  :root {
1436
1438
  ${scaledVars.join("\n")}
1437
1439
  }
1438
- }`
1439
- );
1440
+ }`);
1440
1441
  }
1441
1442
  }
1442
1443
  }
@@ -1801,13 +1802,9 @@ async function buildImageMetadataMap() {
1801
1802
  const webpSrcsetParts = [];
1802
1803
  const avifSrcsetParts = [];
1803
1804
  for (const variant of entry.variants) {
1804
- webpSrcsetParts.push(
1805
- `/images/${encodeURIComponent(variant.webpFilename)} ${variant.width}w`
1806
- );
1805
+ webpSrcsetParts.push(`/images/${encodeURIComponent(variant.webpFilename)} ${variant.width}w`);
1807
1806
  if (variant.avifFilename) {
1808
- avifSrcsetParts.push(
1809
- `/images/${encodeURIComponent(variant.avifFilename)} ${variant.width}w`
1810
- );
1807
+ avifSrcsetParts.push(`/images/${encodeURIComponent(variant.avifFilename)} ${variant.width}w`);
1811
1808
  }
1812
1809
  }
1813
1810
  const hasVariants = entry.variants.length > 0;
@@ -1944,15 +1941,9 @@ function printMissingStyleWarnings(verbose = false) {
1944
1941
  return;
1945
1942
  }
1946
1943
  const warnings = [];
1947
- warnings.push(
1948
- "\n\u26A0\uFE0F WARNING: Found styles that cannot be converted to utility classes\n"
1949
- );
1950
- warnings.push(
1951
- "These styles use object values which cannot be serialized to class names:\n"
1952
- );
1953
- const sorted = Array.from(missingStylesMap.values()).sort(
1954
- (a, b) => b.count - a.count
1955
- );
1944
+ warnings.push("\n\u26A0\uFE0F WARNING: Found styles that cannot be converted to utility classes\n");
1945
+ warnings.push("These styles use object values which cannot be serialized to class names:\n");
1946
+ const sorted = Array.from(missingStylesMap.values()).sort((a, b) => b.count - a.count);
1956
1947
  for (const report of sorted) {
1957
1948
  warnings.push(
1958
1949
  ` \u2022 ${report.property}: "${report.value}" (used ${report.count} time${report.count > 1 ? "s" : ""})`
@@ -1962,9 +1953,7 @@ function printMissingStyleWarnings(verbose = false) {
1962
1953
  warnings.push(` \u2514\u2500 ${location}`);
1963
1954
  }
1964
1955
  if (report.locations.length > 3) {
1965
- warnings.push(
1966
- ` \u2514\u2500 ... and ${report.locations.length - 3} more locations`
1967
- );
1956
+ warnings.push(` \u2514\u2500 ... and ${report.locations.length - 3} more locations`);
1968
1957
  }
1969
1958
  }
1970
1959
  }
@@ -2028,31 +2017,24 @@ function localizeHref(href, ctx) {
2028
2017
  }
2029
2018
  function localizeRichTextLinks(html, ctx) {
2030
2019
  if (ctx.templateMode || !ctx.locale || !ctx.i18nConfig) return html;
2031
- return html.replace(
2032
- /<a\b([^>]*?)href=(["'])([^"']*?)\2([^>]*?)>/gi,
2033
- (match, before, quote, href, after) => {
2034
- if (!href.startsWith("/") || href.startsWith("//")) return match;
2035
- const localized = localizeHref(href, ctx);
2036
- return localized === href ? match : `<a${before}href=${quote}${localized}${quote}${after}>`;
2037
- }
2038
- );
2020
+ return html.replace(/<a\b([^>]*?)href=(["'])([^"']*?)\2([^>]*?)>/gi, (match, before, quote, href, after) => {
2021
+ if (!href.startsWith("/") || href.startsWith("//")) return match;
2022
+ const localized = localizeHref(href, ctx);
2023
+ return localized === href ? match : `<a${before}href=${quote}${localized}${quote}${after}>`;
2024
+ });
2039
2025
  }
2040
2026
  function processStyleToClasses(style, ctx) {
2041
2027
  if (!style) return [];
2042
2028
  let processedStyle = style;
2043
2029
  const templateCtx = getTemplateContext(ctx);
2044
2030
  if (templateCtx && !ctx.templateMode) {
2045
- processedStyle = processItemPropsTemplate(
2046
- style,
2047
- templateCtx,
2048
- getI18nResolver(ctx)
2049
- );
2031
+ processedStyle = processItemPropsTemplate(style, templateCtx, getI18nResolver(ctx));
2050
2032
  }
2051
2033
  const fluidActive = ctx.responsiveScales?.enabled === true && ctx.responsiveScales?.mode === "fluid";
2052
- return responsiveStylesToClasses(
2053
- processedStyle,
2054
- { fluidActive, responsiveScales: ctx.responsiveScales }
2055
- );
2034
+ return responsiveStylesToClasses(processedStyle, {
2035
+ fluidActive,
2036
+ responsiveScales: ctx.responsiveScales
2037
+ });
2056
2038
  }
2057
2039
  function evaluateIfCondition(node, ctx) {
2058
2040
  const ifValue = hasIf(node) ? node.if : void 0;
@@ -2084,31 +2066,53 @@ function evaluateIfCondition(node, ctx) {
2084
2066
  }
2085
2067
  return true;
2086
2068
  }
2069
+ var UNRESOLVED_FILTER_VALUE = Symbol("unresolved-filter-value");
2087
2070
  function resolveFilterValue(value, scope) {
2088
- if (!scope || typeof value !== "string" || !value.startsWith("{{") || !value.endsWith("}}")) {
2071
+ if (typeof value !== "string" || !value.startsWith("{{") || !value.endsWith("}}")) {
2089
2072
  return value;
2090
2073
  }
2091
2074
  const path2 = value.slice(2, -2).trim();
2092
- const resolved = getNestedValue(scope, path2);
2093
- return resolved !== void 0 ? resolved : value;
2094
- }
2095
- function resolveFilterTemplates(filter, scope) {
2096
- if (!filter || !scope) return filter;
2075
+ const resolved = scope ? getNestedValue(scope, path2) : void 0;
2076
+ return resolved !== void 0 ? resolved : UNRESOLVED_FILTER_VALUE;
2077
+ }
2078
+ function resolveFilterTemplates(filter, scope, collection) {
2079
+ if (!filter) return filter;
2080
+ const reportDropped = (field, template) => {
2081
+ logRuntimeError(
2082
+ "ssrRenderer.resolveFilterTemplates",
2083
+ new Error(`Unresolved filter template ${String(template)} \u2014 condition dropped from "${collection}" query`),
2084
+ { collection, field: String(field), template: String(template) }
2085
+ );
2086
+ };
2097
2087
  if (Array.isArray(filter)) {
2098
- return filter.map((cond) => ({
2099
- ...cond,
2100
- value: resolveFilterValue(cond.value, scope)
2101
- }));
2088
+ const conditions = [];
2089
+ for (const cond of filter) {
2090
+ const value = resolveFilterValue(cond.value, scope);
2091
+ if (value === UNRESOLVED_FILTER_VALUE) {
2092
+ reportDropped(cond.field, cond.value);
2093
+ continue;
2094
+ }
2095
+ conditions.push({ ...cond, value });
2096
+ }
2097
+ return conditions;
2102
2098
  }
2103
2099
  if ("field" in filter && "value" in filter) {
2104
- return {
2105
- ...filter,
2106
- value: resolveFilterValue(filter.value, scope)
2107
- };
2100
+ const cond = filter;
2101
+ const value = resolveFilterValue(cond.value, scope);
2102
+ if (value === UNRESOLVED_FILTER_VALUE) {
2103
+ reportDropped(cond.field, cond.value);
2104
+ return void 0;
2105
+ }
2106
+ return { ...cond, value };
2108
2107
  }
2109
2108
  const resolved = {};
2110
2109
  for (const [key, value] of Object.entries(filter)) {
2111
- resolved[key] = resolveFilterValue(value, scope);
2110
+ const resolvedValue = resolveFilterValue(value, scope);
2111
+ if (resolvedValue === UNRESOLVED_FILTER_VALUE) {
2112
+ reportDropped(key, value);
2113
+ continue;
2114
+ }
2115
+ resolved[key] = resolvedValue;
2112
2116
  }
2113
2117
  return resolved;
2114
2118
  }
@@ -2127,12 +2131,11 @@ async function expandRichTextComponents(html, ctx) {
2127
2131
  try {
2128
2132
  const propsStr = match[2].replace(/&quot;/g, '"').replace(/&#039;/g, "'").replace(/&amp;/g, "&");
2129
2133
  props = JSON.parse(propsStr);
2130
- } catch {
2134
+ } catch (error) {
2135
+ logRuntimeError("ssrRenderer.expandRichTextComponents", error, { component: componentName });
2131
2136
  }
2132
2137
  if (ssrComponentRegistry.has(componentName)) {
2133
- parts.push(
2134
- renderComponent(componentName, props, [], {}, ctx)
2135
- );
2138
+ parts.push(renderComponent(componentName, props, [], {}, ctx));
2136
2139
  } else {
2137
2140
  parts.push(match[0]);
2138
2141
  }
@@ -2151,7 +2154,15 @@ async function buildComponentHTML(node, globalComponents = {}, pageComponents =
2151
2154
  const neededCollections = /* @__PURE__ */ new Set();
2152
2155
  const ssrFallbackCollector = /* @__PURE__ */ new Map();
2153
2156
  const processedRawHtmlCollector = /* @__PURE__ */ new Map();
2154
- if (!node) return { html: "", interactiveStylesMap, preloadImages, neededCollections, ssrFallbackCollector, processedRawHtmlCollector };
2157
+ if (!node)
2158
+ return {
2159
+ html: "",
2160
+ interactiveStylesMap,
2161
+ preloadImages,
2162
+ neededCollections,
2163
+ ssrFallbackCollector,
2164
+ processedRawHtmlCollector
2165
+ };
2155
2166
  ssrComponentRegistry.merge(globalComponents);
2156
2167
  ssrComponentRegistry.merge(pageComponents);
2157
2168
  const breakpoints = await loadBreakpointConfig();
@@ -2185,7 +2196,14 @@ async function buildComponentHTML(node, globalComponents = {}, pageComponents =
2185
2196
  responsiveScales: configService.getResponsiveScales()
2186
2197
  };
2187
2198
  const html = await renderNode(node, ctx);
2188
- return { html, interactiveStylesMap, preloadImages, neededCollections, ssrFallbackCollector, processedRawHtmlCollector };
2199
+ return {
2200
+ html,
2201
+ interactiveStylesMap,
2202
+ preloadImages,
2203
+ neededCollections,
2204
+ ssrFallbackCollector,
2205
+ processedRawHtmlCollector
2206
+ };
2189
2207
  }
2190
2208
  async function renderNestedListPlaceholder(node, ctx) {
2191
2209
  const sourceValue = node.source || node.collection;
@@ -2271,13 +2289,7 @@ async function processList(node, ctx) {
2271
2289
  for (let i = 0; i < items.length; i++) {
2272
2290
  const rawItem = items[i];
2273
2291
  const item = schema ? addItemUrl(rawItem, schema, ctx.locale, ctx.i18nConfig) : rawItem;
2274
- const templateContext = buildTemplateContext(
2275
- variableName,
2276
- item,
2277
- i,
2278
- items.length,
2279
- ctx.templateContext
2280
- );
2292
+ const templateContext = buildTemplateContext(variableName, item, i, items.length, ctx.templateContext);
2281
2293
  const itemCtx = {
2282
2294
  ...ctx,
2283
2295
  templateContext,
@@ -2345,7 +2357,11 @@ async function getCollectionItems(node, source, ctx) {
2345
2357
  } else {
2346
2358
  const query = {
2347
2359
  collection: source,
2348
- filter: resolveFilterTemplates(node.filter, buildListResolutionScope(ctx)),
2360
+ filter: resolveFilterTemplates(
2361
+ node.filter,
2362
+ buildListResolutionScope(ctx),
2363
+ source
2364
+ ),
2349
2365
  sort: node.sort,
2350
2366
  limit: node.limit,
2351
2367
  offset: node.offset,
@@ -2488,20 +2504,19 @@ async function renderNode(node, ctx) {
2488
2504
  return escapeHtml(text);
2489
2505
  }
2490
2506
  if (Array.isArray(node)) {
2491
- return (await Promise.all(node.map((child, index) => {
2492
- const childPath = ctx.elementPath ? [...ctx.elementPath.slice(0, -1), index] : [index];
2493
- return renderNode(child, { ...ctx, elementPath: childPath });
2494
- }))).join("");
2507
+ return (await Promise.all(
2508
+ node.map((child, index) => {
2509
+ const childPath = ctx.elementPath ? [...ctx.elementPath.slice(0, -1), index] : [index];
2510
+ return renderNode(child, { ...ctx, elementPath: childPath });
2511
+ })
2512
+ )).join("");
2495
2513
  }
2496
2514
  if (typeof node !== "object") return "";
2497
2515
  if (isI18nValue(node)) {
2498
2516
  const i18nResolveConfig = i18nConfig ?? DEFAULT_I18N_CONFIG;
2499
2517
  const i18nEffectiveLocale = locale || i18nResolveConfig.defaultLocale;
2500
2518
  const resolved = resolveI18nValue(node, i18nEffectiveLocale, i18nResolveConfig);
2501
- return renderNode(
2502
- resolved,
2503
- ctx
2504
- );
2519
+ return renderNode(resolved, ctx);
2505
2520
  }
2506
2521
  if (!evaluateIfCondition(node, ctx)) {
2507
2522
  return "";
@@ -2541,8 +2556,193 @@ async function renderNode(node, ctx) {
2541
2556
  }
2542
2557
  const purify = getDOMPurify();
2543
2558
  const purifiedHtml = purify ? purify.sanitize(htmlContent, {
2544
- ALLOWED_TAGS: ["svg", "path", "circle", "rect", "line", "polyline", "polygon", "g", "text", "tspan", "image", "defs", "use", "linearGradient", "radialGradient", "stop", "clipPath", "mask", "pattern", "marker", "symbol", "a", "div", "span", "p", "br", "button", "img", "iframe", "video", "audio", "source", "canvas", "b", "i", "u", "strong", "em", "sub", "sup", "mark", "s", "small", "del", "ins", "q", "abbr", "code", "pre", "blockquote", "ul", "ol", "li", "h1", "h2", "h3", "h4", "h5", "h6", "style", "animate", "animateTransform", "animateMotion", "set", "filter", "feGaussianBlur", "feOffset", "feMerge", "feMergeNode", "feColorMatrix", "feComposite", "feFlood", "feMorphology", "feBlend", "feDropShadow", "feTurbulence", "feDisplacementMap", "foreignObject"],
2545
- ALLOWED_ATTR: ["class", "id", "style", "width", "height", "viewBox", "xmlns", "xmlns:xlink", "xlink:href", "fill", "stroke", "stroke-width", "stroke-linecap", "stroke-linejoin", "stroke-dasharray", "stroke-dashoffset", "d", "cx", "cy", "r", "x", "y", "x1", "y1", "x2", "y2", "points", "href", "src", "alt", "target", "rel", "data-*", "aria-*", "transform", "opacity", "fill-opacity", "fill-rule", "clip-rule", "clip-path", "clipPathUnits", "mask", "mask-type", "maskUnits", "maskContentUnits", "patternUnits", "patternContentUnits", "patternTransform", "gradientUnits", "gradientTransform", "spreadMethod", "preserveAspectRatio", "marker-start", "marker-mid", "marker-end", "markerUnits", "markerWidth", "markerHeight", "refX", "refY", "orient", "paint-order", "vector-effect", "filter", "filterUnits", "primitiveUnits", "in", "in2", "result", "stdDeviation", "flood-color", "flood-opacity", "stroke-opacity", "font-size", "font-family", "font-weight", "font-style", "text-anchor", "dominant-baseline", "offset", "stop-color", "stop-opacity", "frameborder", "allowfullscreen", "allow", "title", "attributeName", "values", "dur", "begin", "end", "repeatCount", "repeatDur", "keyTimes", "keySplines", "calcMode", "from", "to", "by", "additive", "accumulate", "type", "rotate", "keyPoints", "path"],
2559
+ ALLOWED_TAGS: [
2560
+ "svg",
2561
+ "path",
2562
+ "circle",
2563
+ "rect",
2564
+ "line",
2565
+ "polyline",
2566
+ "polygon",
2567
+ "g",
2568
+ "text",
2569
+ "tspan",
2570
+ "image",
2571
+ "defs",
2572
+ "use",
2573
+ "linearGradient",
2574
+ "radialGradient",
2575
+ "stop",
2576
+ "clipPath",
2577
+ "mask",
2578
+ "pattern",
2579
+ "marker",
2580
+ "symbol",
2581
+ "a",
2582
+ "div",
2583
+ "span",
2584
+ "p",
2585
+ "br",
2586
+ "button",
2587
+ "img",
2588
+ "iframe",
2589
+ "video",
2590
+ "audio",
2591
+ "source",
2592
+ "canvas",
2593
+ "b",
2594
+ "i",
2595
+ "u",
2596
+ "strong",
2597
+ "em",
2598
+ "sub",
2599
+ "sup",
2600
+ "mark",
2601
+ "s",
2602
+ "small",
2603
+ "del",
2604
+ "ins",
2605
+ "q",
2606
+ "abbr",
2607
+ "code",
2608
+ "pre",
2609
+ "blockquote",
2610
+ "ul",
2611
+ "ol",
2612
+ "li",
2613
+ "h1",
2614
+ "h2",
2615
+ "h3",
2616
+ "h4",
2617
+ "h5",
2618
+ "h6",
2619
+ "style",
2620
+ "animate",
2621
+ "animateTransform",
2622
+ "animateMotion",
2623
+ "set",
2624
+ "filter",
2625
+ "feGaussianBlur",
2626
+ "feOffset",
2627
+ "feMerge",
2628
+ "feMergeNode",
2629
+ "feColorMatrix",
2630
+ "feComposite",
2631
+ "feFlood",
2632
+ "feMorphology",
2633
+ "feBlend",
2634
+ "feDropShadow",
2635
+ "feTurbulence",
2636
+ "feDisplacementMap",
2637
+ "foreignObject"
2638
+ ],
2639
+ ALLOWED_ATTR: [
2640
+ "class",
2641
+ "id",
2642
+ "style",
2643
+ "width",
2644
+ "height",
2645
+ "viewBox",
2646
+ "xmlns",
2647
+ "xmlns:xlink",
2648
+ "xlink:href",
2649
+ "fill",
2650
+ "stroke",
2651
+ "stroke-width",
2652
+ "stroke-linecap",
2653
+ "stroke-linejoin",
2654
+ "stroke-dasharray",
2655
+ "stroke-dashoffset",
2656
+ "d",
2657
+ "cx",
2658
+ "cy",
2659
+ "r",
2660
+ "x",
2661
+ "y",
2662
+ "x1",
2663
+ "y1",
2664
+ "x2",
2665
+ "y2",
2666
+ "points",
2667
+ "href",
2668
+ "src",
2669
+ "alt",
2670
+ "target",
2671
+ "rel",
2672
+ "data-*",
2673
+ "aria-*",
2674
+ "transform",
2675
+ "opacity",
2676
+ "fill-opacity",
2677
+ "fill-rule",
2678
+ "clip-rule",
2679
+ "clip-path",
2680
+ "clipPathUnits",
2681
+ "mask",
2682
+ "mask-type",
2683
+ "maskUnits",
2684
+ "maskContentUnits",
2685
+ "patternUnits",
2686
+ "patternContentUnits",
2687
+ "patternTransform",
2688
+ "gradientUnits",
2689
+ "gradientTransform",
2690
+ "spreadMethod",
2691
+ "preserveAspectRatio",
2692
+ "marker-start",
2693
+ "marker-mid",
2694
+ "marker-end",
2695
+ "markerUnits",
2696
+ "markerWidth",
2697
+ "markerHeight",
2698
+ "refX",
2699
+ "refY",
2700
+ "orient",
2701
+ "paint-order",
2702
+ "vector-effect",
2703
+ "filter",
2704
+ "filterUnits",
2705
+ "primitiveUnits",
2706
+ "in",
2707
+ "in2",
2708
+ "result",
2709
+ "stdDeviation",
2710
+ "flood-color",
2711
+ "flood-opacity",
2712
+ "stroke-opacity",
2713
+ "font-size",
2714
+ "font-family",
2715
+ "font-weight",
2716
+ "font-style",
2717
+ "text-anchor",
2718
+ "dominant-baseline",
2719
+ "offset",
2720
+ "stop-color",
2721
+ "stop-opacity",
2722
+ "frameborder",
2723
+ "allowfullscreen",
2724
+ "allow",
2725
+ "title",
2726
+ "attributeName",
2727
+ "values",
2728
+ "dur",
2729
+ "begin",
2730
+ "end",
2731
+ "repeatCount",
2732
+ "repeatDur",
2733
+ "keyTimes",
2734
+ "keySplines",
2735
+ "calcMode",
2736
+ "from",
2737
+ "to",
2738
+ "by",
2739
+ "additive",
2740
+ "accumulate",
2741
+ "type",
2742
+ "rotate",
2743
+ "keyPoints",
2744
+ "path"
2745
+ ],
2546
2746
  KEEP_CONTENT: true
2547
2747
  }) : htmlContent;
2548
2748
  const sanitizedHtml = inlineSvgStyleRules(purifiedHtml);
@@ -2562,7 +2762,7 @@ async function renderNode(node, ctx) {
2562
2762
  if (embedInteractiveStyles && embedInteractiveStyles.length > 0) {
2563
2763
  embedCssVariables = registerInteractiveStyles(ctx, elementClass2, embedInteractiveStyles);
2564
2764
  }
2565
- let embedStyleAttr = buildCssVariableStyleAttr(embedCssVariables);
2765
+ const embedStyleAttr = buildCssVariableStyleAttr(embedCssVariables);
2566
2766
  const attrClassName3 = nodeAttributes2.className || nodeAttributes2.class || "";
2567
2767
  if (attrClassName3) {
2568
2768
  classNames.push(attrClassName3);
@@ -2638,16 +2838,21 @@ async function renderNode(node, ctx) {
2638
2838
  }
2639
2839
  const attrs = buildAttributes(nodeAttributes2, ["href"]);
2640
2840
  const classAttr = ` class="${escapeHtml(classNames.filter(Boolean).join(" "))}"`;
2641
- const childrenHTML = Array.isArray(children) ? (await Promise.all(children.map((child, index) => {
2642
- const childPath = ctx.elementPath ? [...ctx.elementPath, index] : [index];
2643
- return renderNode(child, { ...ctx, elementPath: childPath });
2644
- }))).join("") : await renderNode(children, { ...ctx, elementPath: ctx.elementPath ? [...ctx.elementPath, 0] : [0] });
2841
+ const childrenHTML = Array.isArray(children) ? (await Promise.all(
2842
+ children.map((child, index) => {
2843
+ const childPath = ctx.elementPath ? [...ctx.elementPath, index] : [index];
2844
+ return renderNode(child, { ...ctx, elementPath: childPath });
2845
+ })
2846
+ )).join("") : await renderNode(children, {
2847
+ ...ctx,
2848
+ elementPath: ctx.elementPath ? [...ctx.elementPath, 0] : [0]
2849
+ });
2645
2850
  return `<a href="${escapeHtml(String(href))}"${classAttr}${olinkStyleAttr}${attrs}${editorAttrs(ctx, { isSlotContent: isSlotContent(node) })}>${childrenHTML}</a>`;
2646
2851
  }
2647
2852
  if (isLocaleListNode(node)) {
2648
2853
  return renderLocaleList(node, ctx);
2649
2854
  }
2650
- let tag = isHtmlNode(node) ? node.tag : void 0;
2855
+ const tag = isHtmlNode(node) ? node.tag : void 0;
2651
2856
  const componentName = isComponentNode(node) ? node.component : void 0;
2652
2857
  let nodeProps = isComponentNode(node) ? node.props || {} : {};
2653
2858
  if (ctx.cmsContext?.cms && Object.keys(nodeProps).length > 0) {
@@ -2661,7 +2866,12 @@ async function renderNode(node, ctx) {
2661
2866
  let nodeAttributes = resolveI18nAttrs(extractAttributesFromNode(node), locale, i18nConfig);
2662
2867
  const originalAttributes = { ...nodeAttributes };
2663
2868
  if (ctx.cmsContext?.cms && Object.keys(nodeAttributes).length > 0) {
2664
- nodeAttributes = processCMSPropsTemplate(nodeAttributes, ctx.cmsContext.cms, locale, i18nConfig);
2869
+ nodeAttributes = processCMSPropsTemplate(
2870
+ nodeAttributes,
2871
+ ctx.cmsContext.cms,
2872
+ locale,
2873
+ i18nConfig
2874
+ );
2665
2875
  }
2666
2876
  if (!ctx.templateMode && templateCtx && Object.keys(nodeAttributes).length > 0) {
2667
2877
  nodeAttributes = processItemPropsTemplate(nodeAttributes, templateCtx, i18nResolver);
@@ -2683,7 +2893,12 @@ async function renderNode(node, ctx) {
2683
2893
  }
2684
2894
  } else if (nodeProps.style) {
2685
2895
  if (isResponsiveStyle(nodeProps.style) && breakpoints && viewportWidth) {
2686
- resolvedStyle = mergeResponsiveStyles(nodeProps.style, "viewport", viewportWidth, breakpoints);
2896
+ resolvedStyle = mergeResponsiveStyles(
2897
+ nodeProps.style,
2898
+ "viewport",
2899
+ viewportWidth,
2900
+ breakpoints
2901
+ );
2687
2902
  } else {
2688
2903
  resolvedStyle = nodeProps.style;
2689
2904
  }
@@ -2726,10 +2941,6 @@ async function renderNode(node, ctx) {
2726
2941
  if (tag === "Link") {
2727
2942
  return renderLinkNode(propsWithStyleAndAttrs, children, ctx);
2728
2943
  }
2729
- if (!tag) {
2730
- console.error("Missing tag for HTML element in SSR");
2731
- return "";
2732
- }
2733
2944
  return renderHtmlElement(tag, propsWithStyleAndAttrs, children, ctx);
2734
2945
  }
2735
2946
  async function renderComponent(componentName, propsWithStyleAndAttrs, children, nodeAttributes, ctx) {
@@ -2854,10 +3065,15 @@ async function renderLinkNode(propsWithStyleAndAttrs, children, ctx) {
2854
3065
  const href = localizeHref(rawHref, ctx);
2855
3066
  const linkClassAttr = restProps.className ? ` class="${escapeHtml(String(restProps.className))}"` : "";
2856
3067
  const attrs = buildAttributes(restProps, ["style", "className", "to"]);
2857
- const childrenHTML = Array.isArray(children) ? (await Promise.all(children.map((child, index) => {
2858
- const childPath = ctx.elementPath ? [...ctx.elementPath, index] : [index];
2859
- return renderNode(child, { ...ctx, elementPath: childPath });
2860
- }))).join("") : await renderNode(children, { ...ctx, elementPath: ctx.elementPath ? [...ctx.elementPath, 0] : [0] });
3068
+ const childrenHTML = Array.isArray(children) ? (await Promise.all(
3069
+ children.map((child, index) => {
3070
+ const childPath = ctx.elementPath ? [...ctx.elementPath, index] : [index];
3071
+ return renderNode(child, { ...ctx, elementPath: childPath });
3072
+ })
3073
+ )).join("") : await renderNode(children, {
3074
+ ...ctx,
3075
+ elementPath: ctx.elementPath ? [...ctx.elementPath, 0] : [0]
3076
+ });
2861
3077
  return `<a href="${escapeHtml(String(href))}"${linkClassAttr}${attrs}${editorAttrs(ctx)}>${childrenHTML}</a>`;
2862
3078
  }
2863
3079
  async function renderHtmlElement(tag, propsWithStyleAndAttrs, children, ctx) {
@@ -2888,17 +3104,42 @@ async function renderHtmlElement(tag, propsWithStyleAndAttrs, children, ctx) {
2888
3104
  if (typeof node === "string") return node;
2889
3105
  if (typeof node === "number") return String(node);
2890
3106
  if (Array.isArray(node)) return node.map(flatten).join("");
3107
+ if (node._code === true) return "";
3108
+ logRuntimeError(
3109
+ "ssrRenderer.renderHtmlElement",
3110
+ new Error(`Element child dropped inside <${tag}> \u2014 raw-text elements render only string content`),
3111
+ { tag, droppedNodeType: String(node.type ?? typeof node) }
3112
+ );
2891
3113
  return "";
2892
3114
  };
2893
3115
  childrenHTML = flatten(children);
2894
3116
  } else {
2895
- childrenHTML = Array.isArray(children) ? (await Promise.all(children.map((child, index) => {
2896
- const childPath = ctx.elementPath ? [...ctx.elementPath, index] : [index];
2897
- return renderNode(child, { ...ctx, elementPath: childPath });
2898
- }))).join("") : await renderNode(children, { ...ctx, elementPath: ctx.elementPath ? [...ctx.elementPath, 0] : [0] });
3117
+ childrenHTML = Array.isArray(children) ? (await Promise.all(
3118
+ children.map((child, index) => {
3119
+ const childPath = ctx.elementPath ? [...ctx.elementPath, index] : [index];
3120
+ return renderNode(child, { ...ctx, elementPath: childPath });
3121
+ })
3122
+ )).join("") : await renderNode(children, {
3123
+ ...ctx,
3124
+ elementPath: ctx.elementPath ? [...ctx.elementPath, 0] : [0]
3125
+ });
2899
3126
  }
2900
3127
  const ea = editorAttrs(ctx);
2901
- const voidElements = ["img", "input", "br", "hr", "meta", "link", "area", "base", "col", "embed", "source", "track", "wbr"];
3128
+ const voidElements = [
3129
+ "img",
3130
+ "input",
3131
+ "br",
3132
+ "hr",
3133
+ "meta",
3134
+ "link",
3135
+ "area",
3136
+ "base",
3137
+ "col",
3138
+ "embed",
3139
+ "source",
3140
+ "track",
3141
+ "wbr"
3142
+ ];
2902
3143
  if (voidElements.includes(tag.toLowerCase())) {
2903
3144
  if (tag.toLowerCase() === "img") {
2904
3145
  return renderImageElement(propsWithStyleAndAttrs, classAttr, styleAttr, attrs + ea, ctx);
@@ -2914,8 +3155,8 @@ function renderImageElement(propsWithStyleAndAttrs, classAttr, styleAttr, attrs,
2914
3155
  const loading = imgProps.loading;
2915
3156
  const sizes = imgProps.sizes;
2916
3157
  const fetchpriority = imgProps.fetchpriority;
2917
- let width = imgProps.width;
2918
- let height = imgProps.height;
3158
+ const width = imgProps.width;
3159
+ const height = imgProps.height;
2919
3160
  const metadata = src ? ctx.imageMetadataMap?.get(src) : void 0;
2920
3161
  const sizesAttr = sizes || DEFAULT_SIZES;
2921
3162
  if (fetchpriority === "high" && metadata && ctx.preloadImages) {
@@ -3060,7 +3301,9 @@ function renderLocaleList(node, ctx) {
3060
3301
  break;
3061
3302
  }
3062
3303
  linkContent += `<div>${escapeHtml(displayText)}</div>`;
3063
- links.push(`<a href="${escapeHtml(link.path)}"${hreflangAttr}${currentAttr} data-locale="${escapeHtml(link.locale)}"${classAttrForLink}>${linkContent}</a>`);
3304
+ links.push(
3305
+ `<a href="${escapeHtml(link.path)}"${hreflangAttr}${currentAttr} data-locale="${escapeHtml(link.locale)}"${classAttrForLink}>${linkContent}</a>`
3306
+ );
3064
3307
  }
3065
3308
  const linksHTML = showSeparator ? links.join(`<span${separatorClassAttr}></span>`) : links.join("");
3066
3309
  const nodeAttributes = resolveI18nAttrs(extractAttributesFromNode(node), locale, i18nConfig);
@@ -3093,14 +3336,36 @@ async function renderPageSSR(pageData, globalComponents = {}, pagePath = "/", ba
3093
3336
  meta = { ...meta, ogTitle: processCMSTemplate(meta.ogTitle, cmsContext.cms, effectiveLocale, config) };
3094
3337
  }
3095
3338
  if (typeof meta.ogDescription === "string") {
3096
- meta = { ...meta, ogDescription: processCMSTemplate(meta.ogDescription, cmsContext.cms, effectiveLocale, config) };
3339
+ meta = {
3340
+ ...meta,
3341
+ ogDescription: processCMSTemplate(meta.ogDescription, cmsContext.cms, effectiveLocale, config)
3342
+ };
3097
3343
  }
3098
3344
  if (typeof meta.ogImage === "string") {
3099
3345
  meta = { ...meta, ogImage: processCMSTemplate(meta.ogImage, cmsContext.cms, effectiveLocale, config) };
3100
3346
  }
3101
3347
  }
3102
3348
  const pageComponents = pageData?.components || {};
3103
- const { html: contentHTML, interactiveStylesMap, preloadImages, neededCollections, ssrFallbackCollector, processedRawHtmlCollector } = rootNode ? await buildComponentHTML(rootNode, globalComponents, pageComponents, effectiveLocale, config, slugMappings, pagePath, cmsContext, cmsService, isProductionBuild, injectEditorAttrs) : { html: "", interactiveStylesMap: /* @__PURE__ */ new Map(), preloadImages: [], neededCollections: /* @__PURE__ */ new Set(), ssrFallbackCollector: /* @__PURE__ */ new Map(), processedRawHtmlCollector: /* @__PURE__ */ new Map() };
3349
+ const {
3350
+ html: contentHTML,
3351
+ interactiveStylesMap,
3352
+ preloadImages,
3353
+ neededCollections,
3354
+ ssrFallbackCollector,
3355
+ processedRawHtmlCollector
3356
+ } = await buildComponentHTML(
3357
+ rootNode,
3358
+ globalComponents,
3359
+ pageComponents,
3360
+ effectiveLocale,
3361
+ config,
3362
+ slugMappings,
3363
+ pagePath,
3364
+ cmsContext,
3365
+ cmsService,
3366
+ isProductionBuild,
3367
+ injectEditorAttrs
3368
+ );
3104
3369
  const javascript = await collectComponentJavaScript(globalComponents, pageComponents);
3105
3370
  const componentCSS = collectComponentCSS(globalComponents, pageComponents);
3106
3371
  const fullUrl = baseUrl ? `${baseUrl}${pagePath}` : pagePath;
@@ -3293,7 +3558,9 @@ function generateAllInlineDataScripts(collections) {
3293
3558
  // lib/server/ssr/htmlGenerator.ts
3294
3559
  function generateImagePreloadTags(preloadImages) {
3295
3560
  if (preloadImages.length === 0) return "";
3296
- return preloadImages.map((img) => `<link rel="preload" as="image" type="${img.type}" imagesrcset="${escapeHtml(img.srcset)}" imagesizes="${escapeHtml(img.sizes)}" fetchpriority="high">`).join("\n ");
3561
+ return preloadImages.map(
3562
+ (img) => `<link rel="preload" as="image" type="${img.type}" imagesrcset="${escapeHtml(img.srcset)}" imagesizes="${escapeHtml(img.sizes)}" fetchpriority="high">`
3563
+ ).join("\n ");
3297
3564
  }
3298
3565
  function minifyCSS(code) {
3299
3566
  if (!code.trim()) return code;
@@ -3341,7 +3608,19 @@ async function generateSSRHTML(pageDataOrOptions, globalComponents = {}, pagePat
3341
3608
  cspNonce
3342
3609
  } = options;
3343
3610
  const nonceAttr = cspNonce ? ` nonce="${cspNonce}"` : "";
3344
- const rendered = await renderPageSSR(pageData, components, path2, base, loc, void 0, slugs, cms, cmsServ, isProductionBuild, injectEditorAttrs);
3611
+ const rendered = await renderPageSSR(
3612
+ pageData,
3613
+ components,
3614
+ path2,
3615
+ base,
3616
+ loc,
3617
+ void 0,
3618
+ slugs,
3619
+ cms,
3620
+ cmsServ,
3621
+ isProductionBuild,
3622
+ injectEditorAttrs
3623
+ );
3345
3624
  let finalClientDataCollections = clientDataCollections;
3346
3625
  if (rendered.neededCollections.size > 0 && cmsServ) {
3347
3626
  finalClientDataCollections = clientDataCollections ? new Map(clientDataCollections) : /* @__PURE__ */ new Map();
@@ -3349,9 +3628,7 @@ async function generateSSRHTML(pageDataOrOptions, globalComponents = {}, pagePat
3349
3628
  if (finalClientDataCollections.has(collectionId)) continue;
3350
3629
  const schema = cmsServ.getSchema(collectionId);
3351
3630
  if (!schema?.clientData?.enabled) {
3352
- console.warn(
3353
- `[SSR] Nested collection "${collectionId}" needs clientData.enabled for client-side hydration`
3354
- );
3631
+ console.warn(`[SSR] Nested collection "${collectionId}" needs clientData.enabled for client-side hydration`);
3355
3632
  continue;
3356
3633
  }
3357
3634
  const items = await cmsServ.queryItems({
@@ -3458,8 +3735,18 @@ ${escapedJavaScript}
3458
3735
  const variablesConfig = await variableService.loadConfig();
3459
3736
  const variablesCSS = generateVariablesCSS(variablesConfig, breakpointConfig, responsiveScalesConfig);
3460
3737
  const remConversionConfig = configService.getRemConversion();
3461
- const utilityCSS = generateUtilityCSS(usedUtilityClasses, breakpointConfig, responsiveScalesConfig, remConversionConfig);
3462
- const interactiveCSS = rendered.interactiveStylesMap.size > 0 ? generateAllInteractiveCSS(rendered.interactiveStylesMap, breakpointConfig, remConversionConfig, responsiveScalesConfig) : "";
3738
+ const utilityCSS = generateUtilityCSS(
3739
+ usedUtilityClasses,
3740
+ breakpointConfig,
3741
+ responsiveScalesConfig,
3742
+ remConversionConfig
3743
+ );
3744
+ const interactiveCSS = rendered.interactiveStylesMap.size > 0 ? generateAllInteractiveCSS(
3745
+ rendered.interactiveStylesMap,
3746
+ breakpointConfig,
3747
+ remConversionConfig,
3748
+ responsiveScalesConfig
3749
+ ) : "";
3463
3750
  printMissingStyleWarnings(false);
3464
3751
  const baseCSS = `* {
3465
3752
  margin: 0;
@@ -3493,16 +3780,16 @@ picture {
3493
3780
  display: inline-block;
3494
3781
  vertical-align: top;
3495
3782
  line-height: 0;
3783
+ }
3784
+ /* line-height:0 above kills the inline-block descender gap (inline SVG/icon
3785
+ embeds), but line-height inherits \u2014 so block rich-text inside an <Embed>
3786
+ (CMS content: <p>/<li>/\u2026) would collapse its text lines onto each other.
3787
+ Restore a normal line-height on the embed's children. Astro play renders
3788
+ rich-text bare (no .oem), which is why it looked correct only there. */
3789
+ .oem > * {
3790
+ line-height: normal;
3496
3791
  }`;
3497
- const combinedCSS = [
3498
- fontCSS,
3499
- themeColorVariablesCSS,
3500
- variablesCSS,
3501
- baseCSS,
3502
- componentCSS,
3503
- utilityCSS,
3504
- interactiveCSS
3505
- ].filter(Boolean).join("\n");
3792
+ const combinedCSS = [fontCSS, themeColorVariablesCSS, variablesCSS, baseCSS, componentCSS, utilityCSS, interactiveCSS].filter(Boolean).join("\n");
3506
3793
  const cssWithStableViewport = rewriteViewportUnits(combinedCSS);
3507
3794
  const finalCSS = useBundled ? minifyCSS(cssWithStableViewport) : cssWithStableViewport;
3508
3795
  const prefetchConfig = await loadPrefetchConfig();
@@ -4420,9 +4707,7 @@ var MenoFilter = class _MenoFilter {
4420
4707
  result = result.filter((item) => this.matchesCriteria(item, this.criteria));
4421
4708
  }
4422
4709
  if (this.orCriteria.length > 0) {
4423
- result = result.filter(
4424
- (item) => this.orCriteria.some((criteria) => this.matchesCriteria(item, criteria))
4425
- );
4710
+ result = result.filter((item) => this.orCriteria.some((criteria) => this.matchesCriteria(item, criteria)));
4426
4711
  }
4427
4712
  if (this.searchQuery) {
4428
4713
  const query = this.searchQuery;
@@ -4536,9 +4821,10 @@ var MenoFilter = class _MenoFilter {
4536
4821
  return Array.isArray(opValue) ? opValue.includes(itemValue) : false;
4537
4822
  case "$nin":
4538
4823
  return Array.isArray(opValue) ? !opValue.includes(itemValue) : true;
4539
- case "$empty":
4824
+ case "$empty": {
4540
4825
  const isEmpty = itemValue === void 0 || itemValue === null || itemValue === "" || Array.isArray(itemValue) && itemValue.length === 0;
4541
4826
  return opValue ? isEmpty : !isEmpty;
4827
+ }
4542
4828
  default:
4543
4829
  console.warn(`MenoFilter: Unknown operator "${op}"`);
4544
4830
  return true;
@@ -4644,9 +4930,7 @@ function handleMultiButtonClick(filter, field, value, currentValue) {
4644
4930
  }
4645
4931
  function bindFilterControls(instance) {
4646
4932
  const { wrapper, filter, cleanup } = instance;
4647
- const filterButtons = wrapper.querySelectorAll(
4648
- `[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`
4649
- );
4933
+ const filterButtons = wrapper.querySelectorAll(`[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`);
4650
4934
  for (const btn of filterButtons) {
4651
4935
  if (btn.tagName === "INPUT") continue;
4652
4936
  const field = btn.getAttribute(ATTR.FILTER_FIELD);
@@ -4672,9 +4956,7 @@ function bindFilterControls(instance) {
4672
4956
  btn.addEventListener("click", handler);
4673
4957
  cleanup.push(() => btn.removeEventListener("click", handler));
4674
4958
  }
4675
- const filterCheckboxes = wrapper.querySelectorAll(
4676
- `input[type="checkbox"][${ATTR.FILTER_FIELD}]`
4677
- );
4959
+ const filterCheckboxes = wrapper.querySelectorAll(`input[type="checkbox"][${ATTR.FILTER_FIELD}]`);
4678
4960
  for (const checkbox of filterCheckboxes) {
4679
4961
  const field = checkbox.getAttribute(ATTR.FILTER_FIELD);
4680
4962
  const handler = () => {
@@ -4694,9 +4976,7 @@ function bindFilterControls(instance) {
4694
4976
  checkbox.addEventListener("change", handler);
4695
4977
  cleanup.push(() => checkbox.removeEventListener("change", handler));
4696
4978
  }
4697
- const filterSelects = wrapper.querySelectorAll(
4698
- `select[${ATTR.FILTER_FIELD}]`
4699
- );
4979
+ const filterSelects = wrapper.querySelectorAll(`select[${ATTR.FILTER_FIELD}]`);
4700
4980
  for (const select of filterSelects) {
4701
4981
  const field = select.getAttribute(ATTR.FILTER_FIELD);
4702
4982
  const handler = () => {
@@ -4710,9 +4990,7 @@ function bindFilterControls(instance) {
4710
4990
  select.addEventListener("change", handler);
4711
4991
  cleanup.push(() => select.removeEventListener("change", handler));
4712
4992
  }
4713
- const filterRadios = wrapper.querySelectorAll(
4714
- `input[type="radio"][${ATTR.FILTER_FIELD}]`
4715
- );
4993
+ const filterRadios = wrapper.querySelectorAll(`input[type="radio"][${ATTR.FILTER_FIELD}]`);
4716
4994
  for (const radio of filterRadios) {
4717
4995
  const field = radio.getAttribute(ATTR.FILTER_FIELD);
4718
4996
  const value = radio.getAttribute(ATTR.FILTER_VALUE) || radio.value;
@@ -4733,9 +5011,7 @@ function updateCheckboxFilters(wrapper, filter, field) {
4733
5011
  const checkboxes = wrapper.querySelectorAll(
4734
5012
  `input[type="checkbox"][${ATTR.FILTER_FIELD}="${field}"]:checked`
4735
5013
  );
4736
- const values = Array.from(checkboxes).map(
4737
- (cb) => cb.getAttribute(ATTR.FILTER_VALUE) || cb.value
4738
- );
5014
+ const values = Array.from(checkboxes).map((cb) => cb.getAttribute(ATTR.FILTER_VALUE) || cb.value);
4739
5015
  if (values.length === 0) {
4740
5016
  filter.removeFilter(field);
4741
5017
  } else if (values.length === 1) {
@@ -4823,15 +5099,11 @@ function bindActionControls(instance) {
4823
5099
  }
4824
5100
  }
4825
5101
  function resetFormControls(wrapper) {
4826
- const checkboxes = wrapper.querySelectorAll(
4827
- `input[type="checkbox"][${ATTR.FILTER_FIELD}]`
4828
- );
5102
+ const checkboxes = wrapper.querySelectorAll(`input[type="checkbox"][${ATTR.FILTER_FIELD}]`);
4829
5103
  for (const cb of checkboxes) {
4830
5104
  cb.checked = false;
4831
5105
  }
4832
- const selects = wrapper.querySelectorAll(
4833
- `select[${ATTR.FILTER_FIELD}]`
4834
- );
5106
+ const selects = wrapper.querySelectorAll(`select[${ATTR.FILTER_FIELD}]`);
4835
5107
  for (const select of selects) {
4836
5108
  select.selectedIndex = 0;
4837
5109
  }
@@ -4863,19 +5135,18 @@ function bindPaginationControls(instance) {
4863
5135
  case "last":
4864
5136
  filter.setPage(filter.getPageInfo().total);
4865
5137
  break;
4866
- default:
5138
+ default: {
4867
5139
  const page = parseInt(action || "1", 10);
4868
5140
  if (!isNaN(page)) {
4869
5141
  filter.setPage(page);
4870
5142
  }
5143
+ }
4871
5144
  }
4872
5145
  };
4873
5146
  btn.addEventListener("click", handler);
4874
5147
  cleanup.push(() => btn.removeEventListener("click", handler));
4875
5148
  }
4876
- const perPageSelects = wrapper.querySelectorAll(
4877
- `[${ATTR.PER_PAGE_SELECT}]`
4878
- );
5149
+ const perPageSelects = wrapper.querySelectorAll(`[${ATTR.PER_PAGE_SELECT}]`);
4879
5150
  for (const select of perPageSelects) {
4880
5151
  const handler = () => {
4881
5152
  const perPage = parseInt(select.value, 10);
@@ -5023,9 +5294,7 @@ function renderNestedItemFromTemplate(template, item, itemAs, index, total, pare
5023
5294
  return element;
5024
5295
  }
5025
5296
  function hydrateNestedCMSLists(element, parentItem, parentItemAs) {
5026
- const placeholders = element.querySelectorAll(
5027
- '[data-cms-list-nested="true"]'
5028
- );
5297
+ const placeholders = element.querySelectorAll('[data-cms-list-nested="true"]');
5029
5298
  for (const placeholder of placeholders) {
5030
5299
  hydrateNestedCMSList(placeholder, parentItem, parentItemAs);
5031
5300
  }
@@ -5040,15 +5309,15 @@ function hydrateNestedCMSList(placeholder, parentItem, parentItemAs) {
5040
5309
  return;
5041
5310
  }
5042
5311
  const collection = config.collection;
5043
- const templateEl = placeholder.querySelector(
5044
- "template[data-nested-template]"
5045
- );
5312
+ const templateEl = placeholder.querySelector("template[data-nested-template]");
5046
5313
  if (!templateEl) return;
5047
5314
  const childTemplate = templateEl.innerHTML.trim();
5048
5315
  const nestedItemAs = config.itemAs || singularizeWord(collection);
5049
5316
  const collectionData = getCollectionData(collection);
5050
5317
  if (!collectionData) {
5051
- console.warn(`MenoFilter: No data for nested collection "${collection}". Ensure clientData.enabled is true in schema.`);
5318
+ console.warn(
5319
+ `MenoFilter: No data for nested collection "${collection}". Ensure clientData.enabled is true in schema.`
5320
+ );
5052
5321
  return;
5053
5322
  }
5054
5323
  let items;
@@ -5255,7 +5524,7 @@ function filterDOMOnly(instance, listEl) {
5255
5524
  const sortConfig = filter.getSort();
5256
5525
  const perPage = filter.getPageInfo().perPage;
5257
5526
  const currentPage = filter.getPageInfo().current;
5258
- let filteredItems = items.filter((item) => {
5527
+ const filteredItems = items.filter((item) => {
5259
5528
  for (const [field, value] of Object.entries(filters)) {
5260
5529
  const itemValue = getItemFieldValue(item, field);
5261
5530
  if (!matchesFilter(itemValue, value)) {
@@ -5384,9 +5653,7 @@ function updateFacets(wrapper, filter) {
5384
5653
  function updateActiveFilters(wrapper, filter, instance) {
5385
5654
  const container = wrapper.querySelector(`[${ATTR.ACTIVE_FILTERS}]`);
5386
5655
  if (!container) return;
5387
- const template = wrapper.querySelector(
5388
- `template[${ATTR.ACTIVE_FILTER_TEMPLATE}]`
5389
- );
5656
+ const template = wrapper.querySelector(`template[${ATTR.ACTIVE_FILTER_TEMPLATE}]`);
5390
5657
  const filters = filter.getFilters();
5391
5658
  const entries = Object.entries(filters);
5392
5659
  container.innerHTML = "";
@@ -5517,9 +5784,7 @@ function updateLoadMoreUI(wrapper, filter) {
5517
5784
  function updateActiveStates(wrapper, filter) {
5518
5785
  const filters = filter.getFilters();
5519
5786
  const activeClass = wrapper.getAttribute(ATTR.ACTIVE_CLASS) || "active";
5520
- const filterButtons = wrapper.querySelectorAll(
5521
- `[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`
5522
- );
5787
+ const filterButtons = wrapper.querySelectorAll(`[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`);
5523
5788
  for (const btn of filterButtons) {
5524
5789
  if (btn.tagName === "INPUT") continue;
5525
5790
  const field = btn.getAttribute(ATTR.FILTER_FIELD);
@@ -5752,7 +6017,9 @@ var FileSystemCMSProvider = class {
5752
6017
  */
5753
6018
  validateCollection(collection) {
5754
6019
  if (!isValidIdentifier(collection)) {
5755
- throw new Error(`Invalid collection name: "${collection}". Collection names must contain only letters, numbers, hyphens, and underscores.`);
6020
+ throw new Error(
6021
+ `Invalid collection name: "${collection}". Collection names must contain only letters, numbers, hyphens, and underscores.`
6022
+ );
5756
6023
  }
5757
6024
  }
5758
6025
  /**
@@ -5761,7 +6028,9 @@ var FileSystemCMSProvider = class {
5761
6028
  */
5762
6029
  validateFilename(filename) {
5763
6030
  if (!isSafePathSegment(filename)) {
5764
- throw new Error(`Invalid filename: "${filename}". Filenames cannot contain path separators or traversal sequences.`);
6031
+ throw new Error(
6032
+ `Invalid filename: "${filename}". Filenames cannot contain path separators or traversal sequences.`
6033
+ );
5765
6034
  }
5766
6035
  if (isReservedDraftFilename(filename)) {
5767
6036
  throw new Error(`Invalid filename: "${filename}". The "${CMS_DRAFT_SUFFIX}" suffix is reserved for draft files.`);
@@ -6086,7 +6355,9 @@ var FileSystemCMSProvider = class {
6086
6355
  */
6087
6356
  async saveSchema(collectionId, pageData) {
6088
6357
  if (!isValidIdentifier(collectionId)) {
6089
- throw new Error(`Invalid collection ID: "${collectionId}". Collection IDs must contain only letters, numbers, hyphens, and underscores.`);
6358
+ throw new Error(
6359
+ `Invalid collection ID: "${collectionId}". Collection IDs must contain only letters, numbers, hyphens, and underscores.`
6360
+ );
6090
6361
  }
6091
6362
  const { writeFile: writeFile2, mkdir } = await import("fs/promises");
6092
6363
  if (!existsSync2(this.templatesDir)) {
@@ -6109,7 +6380,9 @@ var FileSystemCMSProvider = class {
6109
6380
  */
6110
6381
  async updateSchema(collectionId, updates) {
6111
6382
  if (!isValidIdentifier(collectionId)) {
6112
- throw new Error(`Invalid collection ID: "${collectionId}". Collection IDs must contain only letters, numbers, hyphens, and underscores.`);
6383
+ throw new Error(
6384
+ `Invalid collection ID: "${collectionId}". Collection IDs must contain only letters, numbers, hyphens, and underscores.`
6385
+ );
6113
6386
  }
6114
6387
  const { readFile, writeFile: writeFile2 } = await import("fs/promises");
6115
6388
  const pageFilePath = join2(this.templatesDir, `${collectionId}.json`);
@@ -6189,4 +6462,4 @@ export {
6189
6462
  FileSystemCMSProvider,
6190
6463
  migrateTemplatesDirectory
6191
6464
  };
6192
- //# sourceMappingURL=chunk-IGYR22T6.js.map
6465
+ //# sourceMappingURL=chunk-2FN4UOVO.js.map