meno-core 1.0.52 → 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 (399) hide show
  1. package/.claude/settings.local.json +1 -3
  2. package/bin/cli.ts +48 -57
  3. package/build-astro.ts +296 -108
  4. package/build-next.ts +1374 -0
  5. package/build-static.test.ts +39 -10
  6. package/build-static.ts +127 -127
  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-CXCBV2M7.js → chunk-2FN4UOVO.js} +581 -502
  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-5ETZFREW.js +514 -0
  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-7NIC4I3V.js → chunk-7HWQUVTU.js} +1691 -1316
  21. package/dist/chunks/chunk-7HWQUVTU.js.map +7 -0
  22. package/dist/chunks/{chunk-EDQSMAMP.js → chunk-AE3QK5QW.js} +189 -19
  23. package/dist/chunks/chunk-AE3QK5QW.js.map +7 -0
  24. package/dist/chunks/{chunk-HNLUO36W.js → chunk-F6KTJYGV.js} +8 -8
  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-H4JSCDNW.js → chunk-GSYYA5GX.js} +25 -2
  29. package/dist/chunks/chunk-GSYYA5GX.js.map +7 -0
  30. package/dist/chunks/{chunk-2QK6U5UK.js → chunk-HIZMY3EP.js} +12 -2
  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-LHLHPYSP.js → chunk-Q4OBWKXG.js} +48 -40
  39. package/dist/chunks/chunk-Q4OBWKXG.js.map +7 -0
  40. package/dist/chunks/{chunk-A725KYFK.js → chunk-QTE32Y53.js} +780 -323
  41. package/dist/chunks/chunk-QTE32Y53.js.map +7 -0
  42. package/dist/chunks/{chunk-LPVETICS.js → chunk-STDY3OVM.js} +397 -84
  43. package/dist/chunks/chunk-STDY3OVM.js.map +7 -0
  44. package/dist/chunks/configService-PRJZF7Y6.js +14 -0
  45. package/dist/chunks/{constants-GWBAD66U.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 +957 -356
  50. package/dist/lib/client/index.js.map +4 -4
  51. package/dist/lib/server/index.js +1538 -328
  52. package/dist/lib/server/index.js.map +4 -4
  53. package/dist/lib/shared/index.js +277 -73
  54. package/dist/lib/shared/index.js.map +4 -4
  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 +14 -172
  59. package/entries/server-router.tsx +1 -7
  60. package/lib/client/ClientInitializer.ts +8 -8
  61. package/lib/client/ErrorBoundary.test.tsx +156 -151
  62. package/lib/client/ErrorBoundary.tsx +184 -121
  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 +335 -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 +246 -54
  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 +137 -89
  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 +68 -0
  79. package/lib/client/fontFamiliesService.ts +69 -0
  80. package/lib/client/hmr/HMRManager.tsx +8 -0
  81. package/lib/client/hmrCssReload.ts +166 -0
  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 +14 -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/index.ts +4 -0
  92. package/lib/client/meno-filter/MenoFilter.test.ts +19 -21
  93. package/lib/client/meno-filter/MenoFilter.ts +5 -9
  94. package/lib/client/meno-filter/bindings.ts +15 -40
  95. package/lib/client/meno-filter/init.ts +1 -1
  96. package/lib/client/meno-filter/renderer.ts +23 -29
  97. package/lib/client/meno-filter/script.generated.ts +1 -3
  98. package/lib/client/meno-filter/ui.ts +5 -5
  99. package/lib/client/meno-filter/updates.ts +15 -21
  100. package/lib/client/navigation.test.ts +159 -159
  101. package/lib/client/navigation.ts +0 -1
  102. package/lib/client/responsiveStyleResolver.test.ts +230 -228
  103. package/lib/client/responsiveStyleResolver.ts +13 -16
  104. package/lib/client/routing/RouteLoader.test.ts +25 -26
  105. package/lib/client/routing/RouteLoader.ts +30 -37
  106. package/lib/client/routing/Router.tsx +112 -18
  107. package/lib/client/scripts/ScriptExecutor.test.ts +270 -128
  108. package/lib/client/scripts/ScriptExecutor.ts +69 -33
  109. package/lib/client/services/PrefetchService.test.ts +2 -2
  110. package/lib/client/services/PrefetchService.ts +10 -24
  111. package/lib/client/styleProcessor.test.ts +9 -9
  112. package/lib/client/styleProcessor.ts +18 -15
  113. package/lib/client/styles/StyleInjector.test.ts +122 -115
  114. package/lib/client/styles/StyleInjector.ts +25 -7
  115. package/lib/client/styles/UtilityClassCollector.ts +26 -27
  116. package/lib/client/styles/cspNonce.test.ts +64 -0
  117. package/lib/client/styles/cspNonce.ts +63 -0
  118. package/lib/client/templateEngine.test.ts +600 -448
  119. package/lib/client/templateEngine.ts +205 -64
  120. package/lib/client/theme.ts +0 -1
  121. package/lib/client/utils/toast.ts +0 -1
  122. package/lib/server/__integration__/api-routes.test.ts +8 -4
  123. package/lib/server/__integration__/cms-integration.test.ts +1 -4
  124. package/lib/server/__integration__/server-lifecycle.test.ts +2 -5
  125. package/lib/server/__integration__/ssr-rendering.test.ts +47 -37
  126. package/lib/server/__integration__/static-assets.test.ts +1 -1
  127. package/lib/server/__integration__/test-helpers.ts +84 -70
  128. package/lib/server/ab/generateFunctions.ts +12 -10
  129. package/lib/server/astro/cmsPageEmitter.ts +47 -32
  130. package/lib/server/astro/componentEmitter.ts +82 -37
  131. package/lib/server/astro/cssCollector.ts +10 -26
  132. package/lib/server/astro/nodeToAstro.test.ts +1750 -30
  133. package/lib/server/astro/nodeToAstro.ts +327 -178
  134. package/lib/server/astro/normalizeOrphanTemplateProps.test.ts +260 -0
  135. package/lib/server/astro/normalizeOrphanTemplateProps.ts +176 -0
  136. package/lib/server/astro/pageEmitter.ts +9 -13
  137. package/lib/server/astro/tailwindMapper.test.ts +10 -37
  138. package/lib/server/astro/tailwindMapper.ts +33 -40
  139. package/lib/server/astro/templateTransformer.ts +14 -17
  140. package/lib/server/createServer.ts +16 -17
  141. package/lib/server/cssGenerator.test.ts +35 -44
  142. package/lib/server/cssGenerator.ts +6 -17
  143. package/lib/server/draftPageStore.ts +49 -0
  144. package/lib/server/fileWatcher.test.ts +124 -10
  145. package/lib/server/fileWatcher.ts +164 -98
  146. package/lib/server/index.ts +20 -2
  147. package/lib/server/jsonLoader.test.ts +39 -2
  148. package/lib/server/jsonLoader.ts +33 -31
  149. package/lib/server/middleware/cors.test.ts +20 -20
  150. package/lib/server/middleware/cors.ts +28 -4
  151. package/lib/server/middleware/errorHandler.test.ts +5 -3
  152. package/lib/server/middleware/errorHandler.ts +3 -8
  153. package/lib/server/middleware/index.ts +0 -1
  154. package/lib/server/middleware/logger.test.ts +7 -5
  155. package/lib/server/middleware/logger.ts +10 -22
  156. package/lib/server/pageCache.test.ts +76 -77
  157. package/lib/server/pageCache.ts +0 -1
  158. package/lib/server/projectContext.ts +4 -3
  159. package/lib/server/providers/fileSystemCMSProvider.test.ts +124 -95
  160. package/lib/server/providers/fileSystemCMSProvider.ts +35 -20
  161. package/lib/server/providers/fileSystemPageProvider.test.ts +84 -0
  162. package/lib/server/providers/fileSystemPageProvider.ts +39 -12
  163. package/lib/server/routes/api/cms.test.ts +26 -14
  164. package/lib/server/routes/api/cms.ts +9 -14
  165. package/lib/server/routes/api/components.ts +35 -34
  166. package/lib/server/routes/api/config.ts +0 -1
  167. package/lib/server/routes/api/core-routes.ts +49 -76
  168. package/lib/server/routes/api/functions.ts +8 -16
  169. package/lib/server/routes/api/index.ts +3 -6
  170. package/lib/server/routes/api/pages.ts +21 -32
  171. package/lib/server/routes/api/shared.test.ts +1 -1
  172. package/lib/server/routes/api/shared.ts +65 -6
  173. package/lib/server/routes/api/variables.test.ts +1 -3
  174. package/lib/server/routes/api/variables.ts +1 -1
  175. package/lib/server/routes/index.ts +106 -19
  176. package/lib/server/routes/pages.ts +47 -35
  177. package/lib/server/routes/static.ts +16 -4
  178. package/lib/server/runtime/bundler.ts +47 -32
  179. package/lib/server/runtime/fs.ts +3 -13
  180. package/lib/server/runtime/httpServer.ts +5 -9
  181. package/lib/server/services/ColorService.ts +32 -27
  182. package/lib/server/services/EnumService.test.ts +2 -6
  183. package/lib/server/services/EnumService.ts +7 -2
  184. package/lib/server/services/VariableService.test.ts +1 -5
  185. package/lib/server/services/VariableService.ts +6 -1
  186. package/lib/server/services/cmsService.test.ts +116 -78
  187. package/lib/server/services/cmsService.ts +24 -54
  188. package/lib/server/services/componentService.test.ts +303 -20
  189. package/lib/server/services/componentService.ts +397 -76
  190. package/lib/server/services/configService.test.ts +9 -31
  191. package/lib/server/services/configService.ts +20 -27
  192. package/lib/server/services/fileWatcherService.ts +44 -30
  193. package/lib/server/services/index.ts +0 -1
  194. package/lib/server/services/pageService.test.ts +24 -3
  195. package/lib/server/services/pageService.ts +135 -16
  196. package/lib/server/ssr/attributeBuilder.ts +24 -8
  197. package/lib/server/ssr/buildErrorOverlay.ts +12 -13
  198. package/lib/server/ssr/clientDataInjector.ts +7 -21
  199. package/lib/server/ssr/cmsSSRProcessor.ts +3 -6
  200. package/lib/server/ssr/cssCollector.ts +1 -1
  201. package/lib/server/ssr/errorOverlay.test.ts +21 -2
  202. package/lib/server/ssr/errorOverlay.ts +39 -18
  203. package/lib/server/ssr/htmlGenerator.nonce.test.ts +3 -9
  204. package/lib/server/ssr/htmlGenerator.test.ts +173 -56
  205. package/lib/server/ssr/htmlGenerator.ts +191 -112
  206. package/lib/server/ssr/imageMetadata.test.ts +3 -1
  207. package/lib/server/ssr/imageMetadata.ts +25 -19
  208. package/lib/server/ssr/jsCollector.test.ts +3 -13
  209. package/lib/server/ssr/jsCollector.ts +3 -8
  210. package/lib/server/ssr/liveReloadIntegration.test.ts +184 -22
  211. package/lib/server/ssr/metaTagGenerator.ts +2 -2
  212. package/lib/server/ssr/ssrRenderer.branches.test.ts +1103 -0
  213. package/lib/server/ssr/ssrRenderer.test.ts +263 -246
  214. package/lib/server/ssr/ssrRenderer.ts +700 -231
  215. package/lib/server/ssrRenderer.test.ts +1044 -950
  216. package/lib/server/utils/jsonLineMapper.test.ts +28 -28
  217. package/lib/server/utils/jsonLineMapper.ts +1 -1
  218. package/lib/server/validateStyleCoverage.ts +18 -20
  219. package/lib/server/webflow/buildWebflow.ts +41 -53
  220. package/lib/server/webflow/nodeToWebflow.test.ts +150 -218
  221. package/lib/server/webflow/nodeToWebflow.ts +195 -258
  222. package/lib/server/webflow/styleMapper.test.ts +15 -56
  223. package/lib/server/webflow/styleMapper.ts +33 -41
  224. package/lib/server/webflow/types.ts +1 -8
  225. package/lib/server/websocketManager.ts +16 -20
  226. package/lib/shared/attributeNodeUtils.test.ts +15 -15
  227. package/lib/shared/attributeNodeUtils.ts +5 -12
  228. package/lib/shared/breakpoints.ts +4 -11
  229. package/lib/shared/cmsQueryParser.test.ts +50 -42
  230. package/lib/shared/cmsQueryParser.ts +49 -31
  231. package/lib/shared/colorVariableUtils.test.ts +5 -5
  232. package/lib/shared/colorVariableUtils.ts +3 -8
  233. package/lib/shared/componentRefs.ts +41 -0
  234. package/lib/shared/constants.test.ts +3 -3
  235. package/lib/shared/constants.ts +12 -8
  236. package/lib/shared/cssGeneration.test.ts +262 -144
  237. package/lib/shared/cssGeneration.ts +189 -514
  238. package/lib/shared/cssNamedColors.ts +152 -30
  239. package/lib/shared/cssProperties.test.ts +5 -6
  240. package/lib/shared/cssProperties.ts +479 -111
  241. package/lib/shared/elementClassName.test.ts +109 -109
  242. package/lib/shared/elementClassName.ts +1 -1
  243. package/lib/shared/elementUtils.ts +12 -16
  244. package/lib/shared/errorLogger.ts +2 -10
  245. package/lib/shared/errors.test.ts +2 -13
  246. package/lib/shared/errors.ts +2 -8
  247. package/lib/shared/expressionEvaluator.test.ts +119 -0
  248. package/lib/shared/expressionEvaluator.ts +95 -22
  249. package/lib/shared/fontCss.ts +101 -0
  250. package/lib/shared/fontLoader.test.ts +19 -5
  251. package/lib/shared/fontLoader.ts +8 -86
  252. package/lib/shared/friendlyError.test.ts +87 -0
  253. package/lib/shared/friendlyError.ts +120 -0
  254. package/lib/shared/gradientUtils.test.ts +1 -5
  255. package/lib/shared/gradientUtils.ts +2 -6
  256. package/lib/shared/hrefRefs.test.ts +130 -0
  257. package/lib/shared/hrefRefs.ts +92 -0
  258. package/lib/shared/i18n.test.ts +1 -1
  259. package/lib/shared/i18n.ts +13 -34
  260. package/lib/shared/index.ts +56 -0
  261. package/lib/shared/inlineSvgStyleRules.test.ts +108 -0
  262. package/lib/shared/inlineSvgStyleRules.ts +132 -0
  263. package/lib/shared/interactiveStyleMappings.test.ts +11 -33
  264. package/lib/shared/interactiveStyleMappings.ts +9 -16
  265. package/lib/shared/interactiveStyles.test.ts +165 -188
  266. package/lib/shared/interfaces/contentProvider.ts +14 -1
  267. package/lib/shared/itemTemplateUtils.test.ts +20 -12
  268. package/lib/shared/itemTemplateUtils.ts +23 -36
  269. package/lib/shared/jsonRepair.ts +8 -2
  270. package/lib/shared/libraryLoader.test.ts +15 -49
  271. package/lib/shared/libraryLoader.ts +7 -22
  272. package/lib/shared/netlifyLocale404.test.ts +179 -0
  273. package/lib/shared/netlifyLocale404.ts +110 -0
  274. package/lib/shared/nodeUtils.test.ts +24 -16
  275. package/lib/shared/nodeUtils.ts +49 -19
  276. package/lib/shared/pathArrayUtils.test.ts +1 -2
  277. package/lib/shared/pathArrayUtils.ts +1 -1
  278. package/lib/shared/pathSecurity.ts +1 -1
  279. package/lib/shared/pathUtils.test.ts +4 -6
  280. package/lib/shared/pathUtils.ts +42 -48
  281. package/lib/shared/paths/Path.test.ts +2 -2
  282. package/lib/shared/paths/Path.ts +0 -1
  283. package/lib/shared/paths/PathConverter.test.ts +1 -1
  284. package/lib/shared/paths/PathConverter.ts +14 -17
  285. package/lib/shared/paths/PathUtils.ts +9 -10
  286. package/lib/shared/paths/PathValidator.test.ts +2 -15
  287. package/lib/shared/paths/PathValidator.ts +11 -9
  288. package/lib/shared/paths/index.ts +1 -2
  289. package/lib/shared/propResolver.test.ts +240 -244
  290. package/lib/shared/propResolver.ts +14 -25
  291. package/lib/shared/pxToRem.test.ts +7 -6
  292. package/lib/shared/pxToRem.ts +2 -5
  293. package/lib/shared/registry/BaseNodeTypeRegistry.test.ts +9 -5
  294. package/lib/shared/registry/ClientRegistry.ts +0 -1
  295. package/lib/shared/registry/ComponentRegistry.test.ts +43 -29
  296. package/lib/shared/registry/ComponentRegistry.ts +9 -11
  297. package/lib/shared/registry/NodeTypeDefinition.ts +15 -8
  298. package/lib/shared/registry/RegistryManager.ts +1 -2
  299. package/lib/shared/registry/SSRRegistry.ts +0 -1
  300. package/lib/shared/registry/createNodeType.ts +7 -9
  301. package/lib/shared/registry/defineNodeType.ts +2 -6
  302. package/lib/shared/registry/index.ts +0 -1
  303. package/lib/shared/registry/nodeTypes/ComponentInstanceNodeType.ts +14 -15
  304. package/lib/shared/registry/nodeTypes/EmbedNodeType.ts +18 -11
  305. package/lib/shared/registry/nodeTypes/HtmlNodeType.ts +47 -18
  306. package/lib/shared/registry/nodeTypes/LinkNodeType.ts +22 -20
  307. package/lib/shared/registry/nodeTypes/ListNodeType.ts +78 -74
  308. package/lib/shared/registry/nodeTypes/LocaleListNodeType.ts +27 -21
  309. package/lib/shared/registry/nodeTypes/SlotMarkerType.ts +6 -7
  310. package/lib/shared/registry/nodeTypes/index.ts +10 -2
  311. package/lib/shared/responsiveScaling.test.ts +15 -31
  312. package/lib/shared/responsiveScaling.ts +55 -37
  313. package/lib/shared/responsiveStyleUtils.ts +11 -13
  314. package/lib/shared/richtext/htmlToTiptap.test.ts +23 -14
  315. package/lib/shared/richtext/htmlToTiptap.ts +1 -3
  316. package/lib/shared/richtext/tiptapToHtml.test.ts +5 -6
  317. package/lib/shared/richtext/types.ts +1 -8
  318. package/lib/shared/slugTranslator.test.ts +37 -13
  319. package/lib/shared/slugTranslator.ts +31 -11
  320. package/lib/shared/slugify.ts +9 -15
  321. package/lib/shared/styleNodeUtils.test.ts +8 -8
  322. package/lib/shared/styleNodeUtils.ts +9 -11
  323. package/lib/shared/styleUtils.test.ts +87 -61
  324. package/lib/shared/styleUtils.ts +5 -6
  325. package/lib/shared/themeDefaults.test.ts +11 -11
  326. package/lib/shared/themeDefaults.ts +3 -4
  327. package/lib/shared/tree/PathBuilder.test.ts +160 -109
  328. package/lib/shared/tree/PathBuilder.ts +121 -59
  329. package/lib/shared/treePathUtils.test.ts +2 -10
  330. package/lib/shared/treePathUtils.ts +54 -59
  331. package/lib/shared/types/api.ts +1 -2
  332. package/lib/shared/types/cms.ts +25 -21
  333. package/lib/shared/types/comment.ts +132 -0
  334. package/lib/shared/types/components.ts +27 -25
  335. package/lib/shared/types/errors.test.ts +1 -6
  336. package/lib/shared/types/errors.ts +3 -7
  337. package/lib/shared/types/experiments.ts +28 -28
  338. package/lib/shared/types/index.ts +14 -2
  339. package/lib/shared/types/rendering.ts +8 -0
  340. package/lib/shared/types/styles.ts +0 -1
  341. package/lib/shared/types/variables.test.ts +4 -13
  342. package/lib/shared/types/variables.ts +48 -27
  343. package/lib/shared/types.ts +1 -2
  344. package/lib/shared/utilityClassConfig.ts +648 -319
  345. package/lib/shared/utilityClassMapper.test.ts +213 -78
  346. package/lib/shared/utilityClassMapper.ts +188 -246
  347. package/lib/shared/utilityClassNames.ts +326 -0
  348. package/lib/shared/utils.test.ts +2 -10
  349. package/lib/shared/utils.ts +19 -10
  350. package/lib/shared/validation/cmsValidators.ts +2 -1
  351. package/lib/shared/validation/commentValidators.test.ts +53 -0
  352. package/lib/shared/validation/commentValidators.ts +80 -0
  353. package/lib/shared/validation/index.ts +1 -0
  354. package/lib/shared/validation/propValidator.test.ts +18 -20
  355. package/lib/shared/validation/propValidator.ts +12 -17
  356. package/lib/shared/validation/schemas.test.ts +24 -33
  357. package/lib/shared/validation/schemas.ts +469 -344
  358. package/lib/shared/validation/validators.test.ts +1 -6
  359. package/lib/shared/validation/validators.ts +89 -68
  360. package/lib/shared/viewportUnits.integration.test.ts +46 -0
  361. package/lib/shared/viewportUnits.test.ts +91 -0
  362. package/lib/shared/viewportUnits.ts +63 -0
  363. package/lib/test-utils/dom-setup.ts +7 -1
  364. package/lib/test-utils/factories/ConsoleMockFactory.ts +3 -7
  365. package/lib/test-utils/factories/DomMockFactory.ts +7 -19
  366. package/lib/test-utils/factories/EventMockFactory.ts +7 -13
  367. package/lib/test-utils/factories/FetchMockFactory.ts +39 -57
  368. package/lib/test-utils/factories/ServerMockFactory.ts +5 -9
  369. package/lib/test-utils/factories/StoreMockFactory.ts +14 -25
  370. package/lib/test-utils/fixtures.ts +45 -45
  371. package/lib/test-utils/helpers/asyncHelpers.test.ts +15 -18
  372. package/lib/test-utils/helpers/asyncHelpers.ts +11 -20
  373. package/lib/test-utils/helpers.ts +1 -5
  374. package/lib/test-utils/index.ts +0 -4
  375. package/lib/test-utils/mockFactories.ts +12 -18
  376. package/lib/test-utils/mocks.ts +4 -2
  377. package/package.json +1 -1
  378. package/scripts/build-meno-filter.ts +1 -4
  379. package/vite.config.ts +4 -4
  380. package/dist/chunks/chunk-2MHDV5BF.js.map +0 -7
  381. package/dist/chunks/chunk-2QK6U5UK.js.map +0 -7
  382. package/dist/chunks/chunk-7NIC4I3V.js.map +0 -7
  383. package/dist/chunks/chunk-A725KYFK.js.map +0 -7
  384. package/dist/chunks/chunk-AZQYF6KE.js.map +0 -7
  385. package/dist/chunks/chunk-CXCBV2M7.js.map +0 -7
  386. package/dist/chunks/chunk-EDQSMAMP.js.map +0 -7
  387. package/dist/chunks/chunk-H4JSCDNW.js.map +0 -7
  388. package/dist/chunks/chunk-HNLUO36W.js.map +0 -7
  389. package/dist/chunks/chunk-I7YIGZXT.js.map +0 -7
  390. package/dist/chunks/chunk-J23ZX5AP.js +0 -241
  391. package/dist/chunks/chunk-J23ZX5AP.js.map +0 -7
  392. package/dist/chunks/chunk-LHLHPYSP.js.map +0 -7
  393. package/dist/chunks/chunk-LPVETICS.js.map +0 -7
  394. package/dist/chunks/chunk-UB44F4Z2.js.map +0 -7
  395. package/dist/chunks/chunk-WQFG7PAH.js.map +0 -7
  396. package/dist/chunks/configService-R3OGU2UD.js +0 -13
  397. /package/dist/chunks/{configService-R3OGU2UD.js.map → configService-PRJZF7Y6.js.map} +0 -0
  398. /package/dist/chunks/{constants-GWBAD66U.js.map → constants-KIQEYMAM.js.map} +0 -0
  399. /package/dist/chunks/{fs-JGINUXGL.js.map → fs-ZI5JEU7V.js.map} +0 -0
@@ -1,32 +1,42 @@
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
+ buildSlugIndex,
18
+ collectComponentLibraries,
19
+ filterLibrariesByContext,
20
+ fontFaceCss,
21
+ fontPreloadLinks,
22
+ generateLibraryTags,
23
+ getLocaleLinks,
17
24
  isReservedDraftFilename,
18
25
  isSafePathSegment,
19
26
  isValidIdentifier,
20
- resolvePaletteColor
21
- } from "./chunk-J23ZX5AP.js";
27
+ mergeLibraries,
28
+ resolvePaletteColor,
29
+ translatePath
30
+ } from "./chunk-5ETZFREW.js";
22
31
  import {
23
32
  extractAttributesFromNode,
33
+ inlineSvgStyleRules,
24
34
  isHtmlMapping,
25
35
  mergeNodeStyles,
26
36
  processStructure,
27
37
  resolveHtmlMapping,
28
38
  skipEmptyTemplateAttributes
29
- } from "./chunk-EDQSMAMP.js";
39
+ } from "./chunk-AE3QK5QW.js";
30
40
  import {
31
41
  DEFAULT_PREFETCH_CONFIG,
32
42
  SSRRegistry,
@@ -62,36 +72,41 @@ import {
62
72
  resolvePropsFromDefinition,
63
73
  resolveTemplateRawValue,
64
74
  responsiveStylesToClasses,
75
+ rewriteViewportUnits,
65
76
  singularize,
77
+ toFriendlyError,
66
78
  validateCMSDraftItem,
67
79
  validateCMSItem,
68
80
  validateComponentDefinition
69
- } from "./chunk-7NIC4I3V.js";
81
+ } from "./chunk-7HWQUVTU.js";
70
82
  import {
71
83
  DEFAULT_BREAKPOINTS,
72
84
  DEFAULT_FLUID_RANGE,
73
- DEFAULT_I18N_CONFIG,
74
85
  DEFAULT_SITE_MARGIN,
75
86
  buildFluidPropertyValue,
76
- buildLocalizedPath,
77
87
  buildSiteMarginClamp,
78
- extractLocaleFromPath,
79
88
  getSmallestBreakpointName,
80
- isI18nValue,
81
- migrateI18nConfig,
89
+ logRuntimeError,
82
90
  normalizeBreakpointConfig,
83
- resolveI18nValue,
84
91
  scalePropertyValue
85
- } 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";
86
101
  import {
87
102
  isTiptapDocument,
88
103
  tiptapToHtml
89
- } from "./chunk-UB44F4Z2.js";
104
+ } from "./chunk-NVRBTSQG.js";
90
105
  import {
91
106
  NODE_TYPE,
92
107
  RAW_HTML_PREFIX,
93
108
  init_constants
94
- } from "./chunk-2QK6U5UK.js";
109
+ } from "./chunk-HIZMY3EP.js";
95
110
  import {
96
111
  __require
97
112
  } from "./chunk-KSBZ2L7C.js";
@@ -167,7 +182,7 @@ function attemptJsonRepair(content) {
167
182
  const nextLine = i + 1 < lines.length ? lines[i + 1] : null;
168
183
  if (nextLine !== null) {
169
184
  const nextTrimmed = nextLine.trimStart();
170
- 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");
171
186
  if (needsComma) {
172
187
  fixed += trimmed + ",\n";
173
188
  if (repairLine === 0) repairLine = i + 1;
@@ -212,6 +227,7 @@ async function loadJSONFile(filePath) {
212
227
  }
213
228
  return null;
214
229
  } catch (error) {
230
+ logRuntimeError("jsonLoader.loadJSONFile", error, { filePath });
215
231
  return null;
216
232
  }
217
233
  }
@@ -225,6 +241,7 @@ async function loadFileAsText(filePath) {
225
241
  }
226
242
  return null;
227
243
  } catch (error) {
244
+ logRuntimeError("jsonLoader.loadFileAsText", error, { filePath });
228
245
  return null;
229
246
  }
230
247
  }
@@ -263,10 +280,7 @@ async function loadSingleComponent(filePath, componentName, category) {
263
280
  const dirPath = filePath.substring(0, filePath.lastIndexOf("/"));
264
281
  const jsFilePath = `${dirPath}/${componentName}.js`;
265
282
  const cssFilePath = `${dirPath}/${componentName}.css`;
266
- const [jsContent, cssContent] = await Promise.all([
267
- loadFileAsText(jsFilePath),
268
- loadFileAsText(cssFilePath)
269
- ]);
283
+ const [jsContent, cssContent] = await Promise.all([loadFileAsText(jsFilePath), loadFileAsText(cssFilePath)]);
270
284
  if (!componentDef.component) {
271
285
  componentDef.component = {};
272
286
  }
@@ -285,6 +299,7 @@ async function loadSingleComponent(filePath, componentName, category) {
285
299
  }
286
300
  return { component: componentDef, warning };
287
301
  } catch (error) {
302
+ logRuntimeError("jsonLoader.loadSingleComponent", error, { filePath, componentName });
288
303
  return { component: null };
289
304
  }
290
305
  }
@@ -366,6 +381,7 @@ async function loadBreakpointConfig() {
366
381
  }
367
382
  }
368
383
  } catch (error) {
384
+ logRuntimeError("jsonLoader.loadBreakpointConfig", error, { filePath: projectPaths.config() });
369
385
  }
370
386
  return { ...DEFAULT_BREAKPOINTS };
371
387
  }
@@ -377,6 +393,7 @@ async function loadI18nConfig() {
377
393
  return migrateI18nConfig(config.i18n);
378
394
  }
379
395
  } catch (error) {
396
+ logRuntimeError("jsonLoader.loadI18nConfig", error, { filePath: projectPaths.config() });
380
397
  }
381
398
  return { ...DEFAULT_I18N_CONFIG };
382
399
  }
@@ -390,6 +407,7 @@ async function loadIconsConfig() {
390
407
  }
391
408
  }
392
409
  } catch (error) {
410
+ logRuntimeError("jsonLoader.loadIconsConfig", error, { filePath: projectPaths.config() });
393
411
  }
394
412
  return {};
395
413
  }
@@ -406,6 +424,7 @@ async function loadPrefetchConfig() {
406
424
  }
407
425
  }
408
426
  } catch (error) {
427
+ logRuntimeError("jsonLoader.loadPrefetchConfig", error, { filePath: projectPaths.config() });
409
428
  }
410
429
  return { ...DEFAULT_PREFETCH_CONFIG };
411
430
  }
@@ -485,44 +504,44 @@ var ColorService = class extends CachedConfigLoader {
485
504
  dark: {
486
505
  label: "Dark",
487
506
  colors: {
488
- "primary": "#007acc",
507
+ primary: "#007acc",
489
508
  "primary-light": "#0099ff",
490
509
  "primary-dark": "#005a99",
491
- "secondary": "#6c757d",
492
- "success": "#28a745",
493
- "warning": "#ffc107",
494
- "danger": "#dc3545",
495
- "error": "#d32f2f",
496
- "info": "#17a2b8",
497
- "light": "#f8f9fa",
498
- "dark": "#343a40",
499
- "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",
500
519
  "text-dark": "#1e1e1e",
501
- "background": "#1e1e1e",
520
+ background: "#1e1e1e",
502
521
  "background-light": "#252526",
503
- "border": "#444444",
522
+ border: "#444444",
504
523
  "border-light": "#d0d0d0"
505
524
  }
506
525
  },
507
526
  light: {
508
527
  label: "Light",
509
528
  colors: {
510
- "primary": "#0066ff",
529
+ primary: "#0066ff",
511
530
  "primary-light": "#3385ff",
512
531
  "primary-dark": "#0052cc",
513
- "secondary": "#888888",
514
- "success": "#22c55e",
515
- "warning": "#f59e0b",
516
- "danger": "#ef4444",
517
- "error": "#dc2626",
518
- "info": "#06b6d4",
519
- "light": "#f8f9fa",
520
- "dark": "#1f2937",
521
- "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",
522
541
  "text-dark": "#ffffff",
523
- "background": "#ffffff",
542
+ background: "#ffffff",
524
543
  "background-light": "#f3f4f6",
525
- "border": "#d1d5db",
544
+ border: "#d1d5db",
526
545
  "border-light": "#e5e7eb"
527
546
  }
528
547
  }
@@ -539,8 +558,8 @@ var ColorService = class extends CachedConfigLoader {
539
558
  default: {
540
559
  label: "Default",
541
560
  colors: {
542
- "background": "#1e1e1e",
543
- "text": "#cccccc"
561
+ background: "#1e1e1e",
562
+ text: "#cccccc"
544
563
  }
545
564
  }
546
565
  }
@@ -561,7 +580,12 @@ var ColorService = class extends CachedConfigLoader {
561
580
  if (data && typeof data === "object" && "themes" in data && "default" in data) {
562
581
  return { status: "valid", config: data, filePath };
563
582
  }
564
- 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
+ };
565
589
  } catch (error) {
566
590
  return {
567
591
  status: "invalid",
@@ -698,7 +722,12 @@ var VariableService = class extends CachedConfigLoader {
698
722
  if (data && typeof data === "object" && "variables" in data && Array.isArray(data.variables)) {
699
723
  return { status: "valid", config: this.migrateConfig(data), filePath };
700
724
  }
701
- 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
+ };
702
731
  } catch (error) {
703
732
  return {
704
733
  status: "invalid",
@@ -966,9 +995,7 @@ var CMSService = class {
966
995
  const slugValue = item[schemaInfo.schema.slugField];
967
996
  if (typeof slugValue === "string") {
968
997
  if (options?.excludeDrafts && defaultLocale && isItemDraftForLocale(item, defaultLocale)) continue;
969
- urls.push(
970
- schemaInfo.schema.urlPattern.replace("{{slug}}", slugValue)
971
- );
998
+ urls.push(schemaInfo.schema.urlPattern.replace("{{slug}}", slugValue));
972
999
  } else if (isI18nValue(slugValue) && locales) {
973
1000
  for (const locale of locales) {
974
1001
  if (options?.excludeDrafts && isItemDraftForLocale(item, locale)) continue;
@@ -985,9 +1012,7 @@ var CMSService = class {
985
1012
  } else if (isI18nValue(slugValue)) {
986
1013
  for (const key of Object.keys(slugValue)) {
987
1014
  if (key !== "_i18n" && typeof slugValue[key] === "string") {
988
- urls.push(
989
- schemaInfo.schema.urlPattern.replace("{{slug}}", slugValue[key])
990
- );
1015
+ urls.push(schemaInfo.schema.urlPattern.replace("{{slug}}", slugValue[key]));
991
1016
  break;
992
1017
  }
993
1018
  }
@@ -1142,14 +1167,10 @@ var CMSService = class {
1142
1167
  */
1143
1168
  applyFilters(items, filter) {
1144
1169
  if (!Array.isArray(filter) && !this.isFilterCondition(filter)) {
1145
- return items.filter(
1146
- (item) => Object.entries(filter).every(([key, value]) => item[key] === value)
1147
- );
1170
+ return items.filter((item) => Object.entries(filter).every(([key, value]) => item[key] === value));
1148
1171
  }
1149
1172
  const conditions = Array.isArray(filter) ? filter : [filter];
1150
- return items.filter(
1151
- (item) => conditions.every((cond) => this.matchCondition(item, cond))
1152
- );
1173
+ return items.filter((item) => conditions.every((cond) => this.matchCondition(item, cond)));
1153
1174
  }
1154
1175
  /**
1155
1176
  * Check if object is a CMSFilterCondition
@@ -1199,9 +1220,7 @@ var CMSService = class {
1199
1220
  }
1200
1221
  const allItems = await this.getCachedItems(collection);
1201
1222
  const itemMap = new Map(allItems.map((item) => [item._id, item]));
1202
- const filenameMap = new Map(
1203
- allItems.filter((item) => item._filename).map((item) => [item._filename, item])
1204
- );
1223
+ const filenameMap = new Map(allItems.filter((item) => item._filename).map((item) => [item._filename, item]));
1205
1224
  return ids.filter(Boolean).map((id) => itemMap.get(id) || filenameMap.get(id)).filter((item) => item !== void 0);
1206
1225
  }
1207
1226
  /**
@@ -1248,7 +1267,9 @@ var CMSService = class {
1248
1267
  const allSchemas = this.getAllSchemas();
1249
1268
  for (const [collectionId, schemaInfo] of allSchemas) {
1250
1269
  const { schema } = schemaInfo;
1251
- 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
+ );
1252
1273
  if (refFields.length === 0) continue;
1253
1274
  const items = await this.getCachedItems(collectionId);
1254
1275
  for (const item of items) {
@@ -1323,57 +1344,11 @@ async function loadProjectConfig() {
1323
1344
  function getProjectConfig() {
1324
1345
  return cachedConfig || { fonts: [] };
1325
1346
  }
1326
- function getFontFormat(path2) {
1327
- if (path2.endsWith(".woff2")) return "woff2";
1328
- if (path2.endsWith(".woff")) return "woff";
1329
- if (path2.endsWith(".ttf")) return "truetype";
1330
- if (path2.endsWith(".otf")) return "opentype";
1331
- return "truetype";
1332
- }
1333
- function extractFamilyName(path2) {
1334
- const filename = path2.split("/").pop() || "Font";
1335
- const name = filename.replace(/\.(ttf|woff2?|otf)$/i, "");
1336
- return name.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
1337
- }
1338
1347
  function generateFontCSS() {
1339
- const config = getProjectConfig();
1340
- const fonts = config.fonts || [];
1341
- return fonts.filter((font) => font.path || font.src).map((font) => {
1342
- const fontPath = font.path || font.src;
1343
- const format = getFontFormat(fontPath);
1344
- const family = font.family || extractFamilyName(fontPath);
1345
- const weight = font.weight ?? 400;
1346
- const weightMax = font.weightMax;
1347
- const style = font.style ?? "normal";
1348
- const fontDisplay = font.fontDisplay;
1349
- const fontWeight = weightMax != null ? `${weight} ${weightMax}` : weight;
1350
- const unicodeRange = font.unicodeRange;
1351
- return `@font-face {
1352
- font-family: '${family}';
1353
- src: url('${fontPath}') format('${format}');
1354
- font-weight: ${fontWeight};
1355
- font-style: ${style};${fontDisplay ? `
1356
- font-display: ${fontDisplay};` : ""}${unicodeRange ? `
1357
- unicode-range: ${unicodeRange};` : ""}
1358
- }`;
1359
- }).join("\n\n");
1360
- }
1361
- function getFontMimeType(path2) {
1362
- if (path2.endsWith(".woff2")) return "font/woff2";
1363
- if (path2.endsWith(".woff")) return "font/woff";
1364
- if (path2.endsWith(".ttf")) return "font/ttf";
1365
- if (path2.endsWith(".otf")) return "font/otf";
1366
- return "font/ttf";
1348
+ return fontFaceCss(getProjectConfig().fonts || []);
1367
1349
  }
1368
1350
  function generateFontPreloadTags() {
1369
- const config = getProjectConfig();
1370
- const fonts = config.fonts || [];
1371
- if (fonts.length === 0) return "";
1372
- return fonts.filter((font) => font.path || font.src).map((font) => {
1373
- const fontPath = font.path || font.src;
1374
- const mimeType = getFontMimeType(fontPath);
1375
- return `<link rel="preload" href="${fontPath}" as="font" type="${mimeType}" crossorigin>`;
1376
- }).join("\n ");
1351
+ return fontPreloadLinks(getProjectConfig().fonts || []);
1377
1352
  }
1378
1353
 
1379
1354
  // lib/server/cssGenerator.ts
@@ -1418,13 +1393,7 @@ function generateVariablesCSS(config, breakpoints, responsiveScales) {
1418
1393
  const categoryScales = responsiveScales?.[v.type];
1419
1394
  const scale = categoryScales?.[smallestBp];
1420
1395
  if (scale != null && scale !== 1) {
1421
- const fluid = buildFluidPropertyValue(
1422
- v.value,
1423
- scale,
1424
- fluidRange.min,
1425
- fluidRange.max,
1426
- fluidBaseRef
1427
- );
1396
+ const fluid = buildFluidPropertyValue(v.value, scale, fluidRange.min, fluidRange.max, fluidBaseRef);
1428
1397
  if (fluid) return ` ${v.cssVar}: ${fluid};`;
1429
1398
  }
1430
1399
  }
@@ -1464,13 +1433,11 @@ ${baseVars.join("\n")}
1464
1433
  }
1465
1434
  }
1466
1435
  if (scaledVars.length > 0) {
1467
- cssBlocks.push(
1468
- `@media (max-width: ${bpEntry.breakpoint}px) {
1436
+ cssBlocks.push(`@media (max-width: ${bpEntry.breakpoint}px) {
1469
1437
  :root {
1470
1438
  ${scaledVars.join("\n")}
1471
1439
  }
1472
- }`
1473
- );
1440
+ }`);
1474
1441
  }
1475
1442
  }
1476
1443
  }
@@ -1553,80 +1520,17 @@ function styleToString(style) {
1553
1520
  const declarations = [];
1554
1521
  for (const [key, value] of Object.entries(style)) {
1555
1522
  if (value === null || value === void 0) continue;
1523
+ const rewritten = rewriteViewportUnits(String(value));
1556
1524
  if (key.startsWith("--")) {
1557
- declarations.push(`${key}: ${escapeHtml(String(value))}`);
1525
+ declarations.push(`${key}: ${escapeHtml(rewritten)}`);
1558
1526
  } else {
1559
1527
  const cssProperty = key.replace(/([A-Z])/g, "-$1").toLowerCase();
1560
- declarations.push(`${cssProperty}: ${escapeHtml(String(value))}`);
1528
+ declarations.push(`${cssProperty}: ${escapeHtml(rewritten)}`);
1561
1529
  }
1562
1530
  }
1563
1531
  return declarations.length > 0 ? declarations.join("; ") : "";
1564
1532
  }
1565
1533
 
1566
- // lib/shared/slugTranslator.ts
1567
- function buildSlugIndex(mappings) {
1568
- const index = /* @__PURE__ */ new Map();
1569
- for (const mapping of mappings) {
1570
- for (const [locale, slug] of Object.entries(mapping.slugs)) {
1571
- const key = `${locale}:${slug}`;
1572
- index.set(key, {
1573
- pageId: mapping.pageId,
1574
- slugs: mapping.slugs
1575
- });
1576
- }
1577
- }
1578
- return index;
1579
- }
1580
- function findPageBySlug(slug, locale, index) {
1581
- const key = `${locale}:${slug}`;
1582
- return index.get(key);
1583
- }
1584
- function translatePath(currentPath, targetLocale, currentLocale, defaultLocale, index) {
1585
- let slug = currentPath;
1586
- if (slug.startsWith("/")) {
1587
- slug = slug.substring(1);
1588
- }
1589
- if (currentLocale !== defaultLocale) {
1590
- if (slug.startsWith(`${currentLocale}/`)) {
1591
- slug = slug.substring(currentLocale.length + 1);
1592
- } else if (slug === currentLocale) {
1593
- slug = "";
1594
- }
1595
- }
1596
- if (slug === "" || slug === "/") {
1597
- slug = "";
1598
- }
1599
- let entry = findPageBySlug(slug, currentLocale, index);
1600
- if (!entry && currentLocale !== defaultLocale) {
1601
- entry = findPageBySlug(slug, defaultLocale, index);
1602
- }
1603
- if (!entry) {
1604
- if (targetLocale === defaultLocale) {
1605
- return slug === "" ? "/" : `/${slug}`;
1606
- }
1607
- return slug === "" ? `/${targetLocale}` : `/${targetLocale}/${slug}`;
1608
- }
1609
- const targetSlug = entry.slugs[targetLocale] ?? entry.slugs[defaultLocale] ?? slug;
1610
- if (targetLocale === defaultLocale) {
1611
- return targetSlug === "" ? "/" : `/${targetSlug}`;
1612
- }
1613
- return targetSlug === "" ? `/${targetLocale}` : `/${targetLocale}/${targetSlug}`;
1614
- }
1615
- function getLocaleLinks(currentPath, currentLocale, i18nConfig, index) {
1616
- return i18nConfig.locales.map((localeConfig) => ({
1617
- locale: localeConfig.code,
1618
- langTag: localeConfig.langTag,
1619
- name: localeConfig.name,
1620
- nativeName: localeConfig.nativeName,
1621
- path: translatePath(currentPath, localeConfig.code, currentLocale, i18nConfig.defaultLocale, index),
1622
- isCurrent: localeConfig.code === currentLocale
1623
- }));
1624
- }
1625
- function resolveSlugToPageId(slug, locale, index) {
1626
- const entry = findPageBySlug(slug, locale, index);
1627
- return entry?.pageId;
1628
- }
1629
-
1630
1534
  // lib/server/ssr/metaTagGenerator.ts
1631
1535
  function extractPageMeta(pageData) {
1632
1536
  const meta = {};
@@ -1898,13 +1802,9 @@ async function buildImageMetadataMap() {
1898
1802
  const webpSrcsetParts = [];
1899
1803
  const avifSrcsetParts = [];
1900
1804
  for (const variant of entry.variants) {
1901
- webpSrcsetParts.push(
1902
- `/images/${encodeURIComponent(variant.webpFilename)} ${variant.width}w`
1903
- );
1805
+ webpSrcsetParts.push(`/images/${encodeURIComponent(variant.webpFilename)} ${variant.width}w`);
1904
1806
  if (variant.avifFilename) {
1905
- avifSrcsetParts.push(
1906
- `/images/${encodeURIComponent(variant.avifFilename)} ${variant.width}w`
1907
- );
1807
+ avifSrcsetParts.push(`/images/${encodeURIComponent(variant.avifFilename)} ${variant.width}w`);
1908
1808
  }
1909
1809
  }
1910
1810
  const hasVariants = entry.variants.length > 0;
@@ -2041,15 +1941,9 @@ function printMissingStyleWarnings(verbose = false) {
2041
1941
  return;
2042
1942
  }
2043
1943
  const warnings = [];
2044
- warnings.push(
2045
- "\n\u26A0\uFE0F WARNING: Found styles that cannot be converted to utility classes\n"
2046
- );
2047
- warnings.push(
2048
- "These styles use object values which cannot be serialized to class names:\n"
2049
- );
2050
- const sorted = Array.from(missingStylesMap.values()).sort(
2051
- (a, b) => b.count - a.count
2052
- );
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);
2053
1947
  for (const report of sorted) {
2054
1948
  warnings.push(
2055
1949
  ` \u2022 ${report.property}: "${report.value}" (used ${report.count} time${report.count > 1 ? "s" : ""})`
@@ -2059,9 +1953,7 @@ function printMissingStyleWarnings(verbose = false) {
2059
1953
  warnings.push(` \u2514\u2500 ${location}`);
2060
1954
  }
2061
1955
  if (report.locations.length > 3) {
2062
- warnings.push(
2063
- ` \u2514\u2500 ... and ${report.locations.length - 3} more locations`
2064
- );
1956
+ warnings.push(` \u2514\u2500 ... and ${report.locations.length - 3} more locations`);
2065
1957
  }
2066
1958
  }
2067
1959
  }
@@ -2125,31 +2017,24 @@ function localizeHref(href, ctx) {
2125
2017
  }
2126
2018
  function localizeRichTextLinks(html, ctx) {
2127
2019
  if (ctx.templateMode || !ctx.locale || !ctx.i18nConfig) return html;
2128
- return html.replace(
2129
- /<a\b([^>]*?)href=(["'])([^"']*?)\2([^>]*?)>/gi,
2130
- (match, before, quote, href, after) => {
2131
- if (!href.startsWith("/") || href.startsWith("//")) return match;
2132
- const localized = localizeHref(href, ctx);
2133
- return localized === href ? match : `<a${before}href=${quote}${localized}${quote}${after}>`;
2134
- }
2135
- );
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
+ });
2136
2025
  }
2137
2026
  function processStyleToClasses(style, ctx) {
2138
2027
  if (!style) return [];
2139
2028
  let processedStyle = style;
2140
2029
  const templateCtx = getTemplateContext(ctx);
2141
2030
  if (templateCtx && !ctx.templateMode) {
2142
- processedStyle = processItemPropsTemplate(
2143
- style,
2144
- templateCtx,
2145
- getI18nResolver(ctx)
2146
- );
2031
+ processedStyle = processItemPropsTemplate(style, templateCtx, getI18nResolver(ctx));
2147
2032
  }
2148
2033
  const fluidActive = ctx.responsiveScales?.enabled === true && ctx.responsiveScales?.mode === "fluid";
2149
- return responsiveStylesToClasses(
2150
- processedStyle,
2151
- { fluidActive, responsiveScales: ctx.responsiveScales }
2152
- );
2034
+ return responsiveStylesToClasses(processedStyle, {
2035
+ fluidActive,
2036
+ responsiveScales: ctx.responsiveScales
2037
+ });
2153
2038
  }
2154
2039
  function evaluateIfCondition(node, ctx) {
2155
2040
  const ifValue = hasIf(node) ? node.if : void 0;
@@ -2181,31 +2066,53 @@ function evaluateIfCondition(node, ctx) {
2181
2066
  }
2182
2067
  return true;
2183
2068
  }
2069
+ var UNRESOLVED_FILTER_VALUE = Symbol("unresolved-filter-value");
2184
2070
  function resolveFilterValue(value, scope) {
2185
- if (!scope || typeof value !== "string" || !value.startsWith("{{") || !value.endsWith("}}")) {
2071
+ if (typeof value !== "string" || !value.startsWith("{{") || !value.endsWith("}}")) {
2186
2072
  return value;
2187
2073
  }
2188
2074
  const path2 = value.slice(2, -2).trim();
2189
- const resolved = getNestedValue(scope, path2);
2190
- return resolved !== void 0 ? resolved : value;
2191
- }
2192
- function resolveFilterTemplates(filter, scope) {
2193
- 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
+ };
2194
2087
  if (Array.isArray(filter)) {
2195
- return filter.map((cond) => ({
2196
- ...cond,
2197
- value: resolveFilterValue(cond.value, scope)
2198
- }));
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;
2199
2098
  }
2200
2099
  if ("field" in filter && "value" in filter) {
2201
- return {
2202
- ...filter,
2203
- value: resolveFilterValue(filter.value, scope)
2204
- };
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 };
2205
2107
  }
2206
2108
  const resolved = {};
2207
2109
  for (const [key, value] of Object.entries(filter)) {
2208
- 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;
2209
2116
  }
2210
2117
  return resolved;
2211
2118
  }
@@ -2224,12 +2131,11 @@ async function expandRichTextComponents(html, ctx) {
2224
2131
  try {
2225
2132
  const propsStr = match[2].replace(/&quot;/g, '"').replace(/&#039;/g, "'").replace(/&amp;/g, "&");
2226
2133
  props = JSON.parse(propsStr);
2227
- } catch {
2134
+ } catch (error) {
2135
+ logRuntimeError("ssrRenderer.expandRichTextComponents", error, { component: componentName });
2228
2136
  }
2229
2137
  if (ssrComponentRegistry.has(componentName)) {
2230
- parts.push(
2231
- renderComponent(componentName, props, [], {}, ctx)
2232
- );
2138
+ parts.push(renderComponent(componentName, props, [], {}, ctx));
2233
2139
  } else {
2234
2140
  parts.push(match[0]);
2235
2141
  }
@@ -2248,7 +2154,15 @@ async function buildComponentHTML(node, globalComponents = {}, pageComponents =
2248
2154
  const neededCollections = /* @__PURE__ */ new Set();
2249
2155
  const ssrFallbackCollector = /* @__PURE__ */ new Map();
2250
2156
  const processedRawHtmlCollector = /* @__PURE__ */ new Map();
2251
- 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
+ };
2252
2166
  ssrComponentRegistry.merge(globalComponents);
2253
2167
  ssrComponentRegistry.merge(pageComponents);
2254
2168
  const breakpoints = await loadBreakpointConfig();
@@ -2282,7 +2196,14 @@ async function buildComponentHTML(node, globalComponents = {}, pageComponents =
2282
2196
  responsiveScales: configService.getResponsiveScales()
2283
2197
  };
2284
2198
  const html = await renderNode(node, ctx);
2285
- return { html, interactiveStylesMap, preloadImages, neededCollections, ssrFallbackCollector, processedRawHtmlCollector };
2199
+ return {
2200
+ html,
2201
+ interactiveStylesMap,
2202
+ preloadImages,
2203
+ neededCollections,
2204
+ ssrFallbackCollector,
2205
+ processedRawHtmlCollector
2206
+ };
2286
2207
  }
2287
2208
  async function renderNestedListPlaceholder(node, ctx) {
2288
2209
  const sourceValue = node.source || node.collection;
@@ -2312,6 +2233,13 @@ async function renderNestedListPlaceholder(node, ctx) {
2312
2233
  const configJson = escapeHtml(JSON.stringify(config));
2313
2234
  return `<div data-cms-list-nested="true" data-collection="${escapeHtml(sourceStr)}" data-cms-config="${configJson}"${editorAttrs(ctx, { isCMSListContainer: true })}><template data-nested-template>${templateContent}</template></div>`;
2314
2235
  }
2236
+ function renderNodeFallback(ctx, error, label) {
2237
+ console.error(`\u274C SSR render error in ${label}:`, error);
2238
+ if (!ctx.injectEditorAttrs) return "";
2239
+ const friendly = toFriendlyError(error);
2240
+ const text = `${friendly.title} \u2014 ${friendly.friendlyMessage}`;
2241
+ return `<div data-meno-render-error style="margin:8px 0;padding:12px 14px;border:1px dashed #e0a3a3;border-radius:6px;background:#fdf3f3;color:#9a3b3b;font:13px/1.5 -apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">\u26A0\uFE0F ${escapeHtml(text)}</div>`;
2242
+ }
2315
2243
  async function processList(node, ctx) {
2316
2244
  const nodeType = node.type;
2317
2245
  const isLegacyCMSList = nodeType === "cms-list";
@@ -2346,6 +2274,7 @@ async function processList(node, ctx) {
2346
2274
  items = [];
2347
2275
  }
2348
2276
  }
2277
+ if (!Array.isArray(items)) items = [];
2349
2278
  if (node.offset && sourceType === "prop") {
2350
2279
  items = items.slice(node.offset);
2351
2280
  }
@@ -2360,13 +2289,7 @@ async function processList(node, ctx) {
2360
2289
  for (let i = 0; i < items.length; i++) {
2361
2290
  const rawItem = items[i];
2362
2291
  const item = schema ? addItemUrl(rawItem, schema, ctx.locale, ctx.i18nConfig) : rawItem;
2363
- const templateContext = buildTemplateContext(
2364
- variableName,
2365
- item,
2366
- i,
2367
- items.length,
2368
- ctx.templateContext
2369
- );
2292
+ const templateContext = buildTemplateContext(variableName, item, i, items.length, ctx.templateContext);
2370
2293
  const itemCtx = {
2371
2294
  ...ctx,
2372
2295
  templateContext,
@@ -2434,7 +2357,11 @@ async function getCollectionItems(node, source, ctx) {
2434
2357
  } else {
2435
2358
  const query = {
2436
2359
  collection: source,
2437
- filter: resolveFilterTemplates(node.filter, buildListResolutionScope(ctx)),
2360
+ filter: resolveFilterTemplates(
2361
+ node.filter,
2362
+ buildListResolutionScope(ctx),
2363
+ source
2364
+ ),
2438
2365
  sort: node.sort,
2439
2366
  limit: node.limit,
2440
2367
  offset: node.offset,
@@ -2512,7 +2439,7 @@ function registerInteractiveStyles(ctx, elementClass, interactiveStyles) {
2512
2439
  }
2513
2440
  function buildCssVariableStyleAttr(cssVariables) {
2514
2441
  if (Object.keys(cssVariables).length === 0) return "";
2515
- const styleString = Object.entries(cssVariables).map(([k, v]) => `${k}: ${v}`).join("; ");
2442
+ const styleString = Object.entries(cssVariables).map(([k, v]) => `${k}: ${rewriteViewportUnits(v)}`).join("; ");
2516
2443
  return ` style="${escapeHtml(styleString)}"`;
2517
2444
  }
2518
2445
  function arraysEqual(a, b) {
@@ -2538,6 +2465,9 @@ function editorAttrs(ctx, opts = {}) {
2538
2465
  async function renderNode(node, ctx) {
2539
2466
  const { breakpoints, viewportWidth, locale, i18nConfig, slugMappings, pagePath } = ctx;
2540
2467
  if (node === null || node === void 0) return "";
2468
+ if (typeof node === "object" && !Array.isArray(node) && node._code === true) {
2469
+ return "";
2470
+ }
2541
2471
  if (typeof node === "string" || typeof node === "number") {
2542
2472
  let text = String(node);
2543
2473
  if (ctx.templateMode) {
@@ -2574,26 +2504,29 @@ async function renderNode(node, ctx) {
2574
2504
  return escapeHtml(text);
2575
2505
  }
2576
2506
  if (Array.isArray(node)) {
2577
- return (await Promise.all(node.map((child, index) => {
2578
- const childPath = ctx.elementPath ? [...ctx.elementPath.slice(0, -1), index] : [index];
2579
- return renderNode(child, { ...ctx, elementPath: childPath });
2580
- }))).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("");
2581
2513
  }
2582
2514
  if (typeof node !== "object") return "";
2583
2515
  if (isI18nValue(node)) {
2584
2516
  const i18nResolveConfig = i18nConfig ?? DEFAULT_I18N_CONFIG;
2585
2517
  const i18nEffectiveLocale = locale || i18nResolveConfig.defaultLocale;
2586
2518
  const resolved = resolveI18nValue(node, i18nEffectiveLocale, i18nResolveConfig);
2587
- return renderNode(
2588
- resolved,
2589
- ctx
2590
- );
2519
+ return renderNode(resolved, ctx);
2591
2520
  }
2592
2521
  if (!evaluateIfCondition(node, ctx)) {
2593
2522
  return "";
2594
2523
  }
2595
2524
  if (isListNode(node)) {
2596
- return await processList(node, ctx);
2525
+ try {
2526
+ return await processList(node, ctx);
2527
+ } catch (error) {
2528
+ return renderNodeFallback(ctx, error, "list");
2529
+ }
2597
2530
  }
2598
2531
  const nodeType = "type" in node ? node.type : void 0;
2599
2532
  const nodeStyle = "style" in node ? node.style : void 0;
@@ -2622,11 +2555,197 @@ async function renderNode(node, ctx) {
2622
2555
  }
2623
2556
  }
2624
2557
  const purify = getDOMPurify();
2625
- const sanitizedHtml = purify ? purify.sanitize(htmlContent, {
2626
- 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"],
2627
- ALLOWED_ATTR: ["class", "id", "style", "width", "height", "viewBox", "xmlns", "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", "stroke-opacity", "font-size", "font-family", "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"],
2558
+ const purifiedHtml = purify ? purify.sanitize(htmlContent, {
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
+ ],
2628
2746
  KEEP_CONTENT: true
2629
2747
  }) : htmlContent;
2748
+ const sanitizedHtml = inlineSvgStyleRules(purifiedHtml);
2630
2749
  const optimizedHtml = ctx.imageMetadataMap ? rewriteRichTextImages(sanitizedHtml, ctx.imageMetadataMap, ctx.imageFormat) : sanitizedHtml;
2631
2750
  const nodeAttributes2 = resolveI18nAttrs(extractAttributesFromNode(node), locale, i18nConfig);
2632
2751
  const classNames = ["oem"];
@@ -2643,7 +2762,7 @@ async function renderNode(node, ctx) {
2643
2762
  if (embedInteractiveStyles && embedInteractiveStyles.length > 0) {
2644
2763
  embedCssVariables = registerInteractiveStyles(ctx, elementClass2, embedInteractiveStyles);
2645
2764
  }
2646
- let embedStyleAttr = buildCssVariableStyleAttr(embedCssVariables);
2765
+ const embedStyleAttr = buildCssVariableStyleAttr(embedCssVariables);
2647
2766
  const attrClassName3 = nodeAttributes2.className || nodeAttributes2.class || "";
2648
2767
  if (attrClassName3) {
2649
2768
  classNames.push(attrClassName3);
@@ -2719,16 +2838,21 @@ async function renderNode(node, ctx) {
2719
2838
  }
2720
2839
  const attrs = buildAttributes(nodeAttributes2, ["href"]);
2721
2840
  const classAttr = ` class="${escapeHtml(classNames.filter(Boolean).join(" "))}"`;
2722
- const childrenHTML = Array.isArray(children) ? (await Promise.all(children.map((child, index) => {
2723
- const childPath = ctx.elementPath ? [...ctx.elementPath, index] : [index];
2724
- return renderNode(child, { ...ctx, elementPath: childPath });
2725
- }))).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
+ });
2726
2850
  return `<a href="${escapeHtml(String(href))}"${classAttr}${olinkStyleAttr}${attrs}${editorAttrs(ctx, { isSlotContent: isSlotContent(node) })}>${childrenHTML}</a>`;
2727
2851
  }
2728
2852
  if (isLocaleListNode(node)) {
2729
2853
  return renderLocaleList(node, ctx);
2730
2854
  }
2731
- let tag = isHtmlNode(node) ? node.tag : void 0;
2855
+ const tag = isHtmlNode(node) ? node.tag : void 0;
2732
2856
  const componentName = isComponentNode(node) ? node.component : void 0;
2733
2857
  let nodeProps = isComponentNode(node) ? node.props || {} : {};
2734
2858
  if (ctx.cmsContext?.cms && Object.keys(nodeProps).length > 0) {
@@ -2742,7 +2866,12 @@ async function renderNode(node, ctx) {
2742
2866
  let nodeAttributes = resolveI18nAttrs(extractAttributesFromNode(node), locale, i18nConfig);
2743
2867
  const originalAttributes = { ...nodeAttributes };
2744
2868
  if (ctx.cmsContext?.cms && Object.keys(nodeAttributes).length > 0) {
2745
- nodeAttributes = processCMSPropsTemplate(nodeAttributes, ctx.cmsContext.cms, locale, i18nConfig);
2869
+ nodeAttributes = processCMSPropsTemplate(
2870
+ nodeAttributes,
2871
+ ctx.cmsContext.cms,
2872
+ locale,
2873
+ i18nConfig
2874
+ );
2746
2875
  }
2747
2876
  if (!ctx.templateMode && templateCtx && Object.keys(nodeAttributes).length > 0) {
2748
2877
  nodeAttributes = processItemPropsTemplate(nodeAttributes, templateCtx, i18nResolver);
@@ -2764,7 +2893,12 @@ async function renderNode(node, ctx) {
2764
2893
  }
2765
2894
  } else if (nodeProps.style) {
2766
2895
  if (isResponsiveStyle(nodeProps.style) && breakpoints && viewportWidth) {
2767
- resolvedStyle = mergeResponsiveStyles(nodeProps.style, "viewport", viewportWidth, breakpoints);
2896
+ resolvedStyle = mergeResponsiveStyles(
2897
+ nodeProps.style,
2898
+ "viewport",
2899
+ viewportWidth,
2900
+ breakpoints
2901
+ );
2768
2902
  } else {
2769
2903
  resolvedStyle = nodeProps.style;
2770
2904
  }
@@ -2807,10 +2941,6 @@ async function renderNode(node, ctx) {
2807
2941
  if (tag === "Link") {
2808
2942
  return renderLinkNode(propsWithStyleAndAttrs, children, ctx);
2809
2943
  }
2810
- if (!tag) {
2811
- console.error("Missing tag for HTML element in SSR");
2812
- return "";
2813
- }
2814
2944
  return renderHtmlElement(tag, propsWithStyleAndAttrs, children, ctx);
2815
2945
  }
2816
2946
  async function renderComponent(componentName, propsWithStyleAndAttrs, children, nodeAttributes, ctx) {
@@ -2830,7 +2960,17 @@ async function renderComponent(componentName, propsWithStyleAndAttrs, children,
2830
2960
  const markedChildren = children ? markAsSlotContent(children) : void 0;
2831
2961
  const processedStructure = processStructure(
2832
2962
  structuredComponentDef.structure,
2833
- { props: resolvedProps, componentDef: structuredComponentDef, itemContext: ctx.templateContext },
2963
+ {
2964
+ props: resolvedProps,
2965
+ componentDef: structuredComponentDef,
2966
+ itemContext: ctx.templateContext,
2967
+ // Host (outer) component's resolved props — used as fallback scope
2968
+ // for `{{x}}` templates the child's interface doesn't declare. At
2969
+ // this point `ctx.componentResolvedProps` still belongs to the
2970
+ // outer component; it's only swapped to `resolvedProps` below when
2971
+ // we recurse via `renderNode`.
2972
+ parentProps: ctx.componentResolvedProps
2973
+ },
2834
2974
  void 0,
2835
2975
  markedChildren,
2836
2976
  true
@@ -2894,6 +3034,16 @@ async function renderComponent(componentName, propsWithStyleAndAttrs, children,
2894
3034
  existingPropsMap[componentName] = propsForJS;
2895
3035
  processedRoot.attributes["data-props"] = JSON.stringify(existingPropsMap);
2896
3036
  }
3037
+ if (componentName && (isHtmlNode(rootNode) || isLinkNode(rootNode))) {
3038
+ if (!rootNode.attributes) rootNode.attributes = {};
3039
+ if (!ctx.componentInstanceCounter) {
3040
+ ctx.componentInstanceCounter = /* @__PURE__ */ new Map();
3041
+ }
3042
+ const instanceIndex = ctx.componentInstanceCounter.get(componentName) ?? 0;
3043
+ ctx.componentInstanceCounter.set(componentName, instanceIndex + 1);
3044
+ rootNode.attributes["data-meno-component"] = componentName;
3045
+ rootNode.attributes["data-meno-component-instance"] = String(instanceIndex);
3046
+ }
2897
3047
  }
2898
3048
  return await renderNode(processedStructure, {
2899
3049
  ...ctx,
@@ -2904,8 +3054,7 @@ async function renderComponent(componentName, propsWithStyleAndAttrs, children,
2904
3054
  componentResolvedProps: resolvedProps
2905
3055
  });
2906
3056
  } catch (error) {
2907
- console.error(`\u274C SSR Error rendering component ${componentName}:`, error);
2908
- return "";
3057
+ return renderNodeFallback(ctx, error, `component ${componentName}`);
2909
3058
  }
2910
3059
  }
2911
3060
  async function renderLinkNode(propsWithStyleAndAttrs, children, ctx) {
@@ -2916,10 +3065,15 @@ async function renderLinkNode(propsWithStyleAndAttrs, children, ctx) {
2916
3065
  const href = localizeHref(rawHref, ctx);
2917
3066
  const linkClassAttr = restProps.className ? ` class="${escapeHtml(String(restProps.className))}"` : "";
2918
3067
  const attrs = buildAttributes(restProps, ["style", "className", "to"]);
2919
- const childrenHTML = Array.isArray(children) ? (await Promise.all(children.map((child, index) => {
2920
- const childPath = ctx.elementPath ? [...ctx.elementPath, index] : [index];
2921
- return renderNode(child, { ...ctx, elementPath: childPath });
2922
- }))).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
+ });
2923
3077
  return `<a href="${escapeHtml(String(href))}"${linkClassAttr}${attrs}${editorAttrs(ctx)}>${childrenHTML}</a>`;
2924
3078
  }
2925
3079
  async function renderHtmlElement(tag, propsWithStyleAndAttrs, children, ctx) {
@@ -2950,17 +3104,42 @@ async function renderHtmlElement(tag, propsWithStyleAndAttrs, children, ctx) {
2950
3104
  if (typeof node === "string") return node;
2951
3105
  if (typeof node === "number") return String(node);
2952
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
+ );
2953
3113
  return "";
2954
3114
  };
2955
3115
  childrenHTML = flatten(children);
2956
3116
  } else {
2957
- childrenHTML = Array.isArray(children) ? (await Promise.all(children.map((child, index) => {
2958
- const childPath = ctx.elementPath ? [...ctx.elementPath, index] : [index];
2959
- return renderNode(child, { ...ctx, elementPath: childPath });
2960
- }))).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
+ });
2961
3126
  }
2962
3127
  const ea = editorAttrs(ctx);
2963
- 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
+ ];
2964
3143
  if (voidElements.includes(tag.toLowerCase())) {
2965
3144
  if (tag.toLowerCase() === "img") {
2966
3145
  return renderImageElement(propsWithStyleAndAttrs, classAttr, styleAttr, attrs + ea, ctx);
@@ -2976,8 +3155,8 @@ function renderImageElement(propsWithStyleAndAttrs, classAttr, styleAttr, attrs,
2976
3155
  const loading = imgProps.loading;
2977
3156
  const sizes = imgProps.sizes;
2978
3157
  const fetchpriority = imgProps.fetchpriority;
2979
- let width = imgProps.width;
2980
- let height = imgProps.height;
3158
+ const width = imgProps.width;
3159
+ const height = imgProps.height;
2981
3160
  const metadata = src ? ctx.imageMetadataMap?.get(src) : void 0;
2982
3161
  const sizesAttr = sizes || DEFAULT_SIZES;
2983
3162
  if (fetchpriority === "high" && metadata && ctx.preloadImages) {
@@ -3122,7 +3301,9 @@ function renderLocaleList(node, ctx) {
3122
3301
  break;
3123
3302
  }
3124
3303
  linkContent += `<div>${escapeHtml(displayText)}</div>`;
3125
- 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
+ );
3126
3307
  }
3127
3308
  const linksHTML = showSeparator ? links.join(`<span${separatorClassAttr}></span>`) : links.join("");
3128
3309
  const nodeAttributes = resolveI18nAttrs(extractAttributesFromNode(node), locale, i18nConfig);
@@ -3155,11 +3336,36 @@ async function renderPageSSR(pageData, globalComponents = {}, pagePath = "/", ba
3155
3336
  meta = { ...meta, ogTitle: processCMSTemplate(meta.ogTitle, cmsContext.cms, effectiveLocale, config) };
3156
3337
  }
3157
3338
  if (typeof meta.ogDescription === "string") {
3158
- meta = { ...meta, ogDescription: processCMSTemplate(meta.ogDescription, cmsContext.cms, effectiveLocale, config) };
3339
+ meta = {
3340
+ ...meta,
3341
+ ogDescription: processCMSTemplate(meta.ogDescription, cmsContext.cms, effectiveLocale, config)
3342
+ };
3343
+ }
3344
+ if (typeof meta.ogImage === "string") {
3345
+ meta = { ...meta, ogImage: processCMSTemplate(meta.ogImage, cmsContext.cms, effectiveLocale, config) };
3159
3346
  }
3160
3347
  }
3161
3348
  const pageComponents = pageData?.components || {};
3162
- 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
+ );
3163
3369
  const javascript = await collectComponentJavaScript(globalComponents, pageComponents);
3164
3370
  const componentCSS = collectComponentCSS(globalComponents, pageComponents);
3165
3371
  const fullUrl = baseUrl ? `${baseUrl}${pagePath}` : pagePath;
@@ -3349,138 +3555,12 @@ function generateAllInlineDataScripts(collections) {
3349
3555
  return scripts.join("\n ");
3350
3556
  }
3351
3557
 
3352
- // lib/shared/libraryLoader.ts
3353
- function escapeAttr2(str) {
3354
- return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3355
- }
3356
- function mergeLibraries(global, page) {
3357
- if (!page) {
3358
- return global;
3359
- }
3360
- if (page.mode === "replace") {
3361
- return {
3362
- js: page.js || [],
3363
- css: page.css || []
3364
- };
3365
- }
3366
- return {
3367
- js: [...global.js || [], ...page.js || []],
3368
- css: [...global.css || [], ...page.css || []]
3369
- };
3370
- }
3371
- function generateScriptTag(lib) {
3372
- const attrs = [`src="${escapeAttr2(lib.url)}"`];
3373
- if (lib.type === "module") {
3374
- attrs.push('type="module"');
3375
- } else {
3376
- const mode = lib.mode || "defer";
3377
- attrs.push(mode);
3378
- }
3379
- return `<script ${attrs.join(" ")}></script>`;
3380
- }
3381
- function generateInlineStyleTag(content, media) {
3382
- const attrs = media ? ` media="${escapeAttr2(media)}"` : "";
3383
- return `<style${attrs}>${content}</style>`;
3384
- }
3385
- function generateStylesheetTag(lib) {
3386
- const attrs = [
3387
- 'rel="stylesheet"',
3388
- `href="${escapeAttr2(lib.url)}"`
3389
- ];
3390
- if (lib.media) {
3391
- attrs.push(`media="${escapeAttr2(lib.media)}"`);
3392
- }
3393
- return `<link ${attrs.join(" ")}>`;
3394
- }
3395
- function generateLibraryTags(libs, inlineContents) {
3396
- const headCSS = [];
3397
- const headJS = [];
3398
- const bodyEndJS = [];
3399
- for (const css of libs.css || []) {
3400
- const inlineContent = inlineContents?.get(css.url);
3401
- if (inlineContent !== void 0) {
3402
- headCSS.push(generateInlineStyleTag(inlineContent, css.media));
3403
- } else {
3404
- headCSS.push(generateStylesheetTag(css));
3405
- }
3406
- }
3407
- for (const js of libs.js || []) {
3408
- const tag = generateScriptTag(js);
3409
- if (js.position === "head") {
3410
- headJS.push(tag);
3411
- } else {
3412
- bodyEndJS.push(tag);
3413
- }
3414
- }
3415
- return {
3416
- headCSS: headCSS.join("\n "),
3417
- headJS: headJS.join("\n "),
3418
- bodyEndJS: bodyEndJS.join("\n ")
3419
- };
3420
- }
3421
- function collectComponentLibraries(globalComponents = {}, pageComponents = {}) {
3422
- const seenJS = /* @__PURE__ */ new Set();
3423
- const seenCSS = /* @__PURE__ */ new Set();
3424
- const jsLibs = [];
3425
- const cssLibs = [];
3426
- const collect = (components) => {
3427
- for (const component of Object.values(components)) {
3428
- const libs = component?.component?.libraries;
3429
- if (!libs) continue;
3430
- for (const js of libs.js || []) {
3431
- if (!seenJS.has(js.url)) {
3432
- seenJS.add(js.url);
3433
- jsLibs.push(js);
3434
- }
3435
- }
3436
- for (const css of libs.css || []) {
3437
- if (!seenCSS.has(css.url)) {
3438
- seenCSS.add(css.url);
3439
- cssLibs.push(css);
3440
- }
3441
- }
3442
- }
3443
- };
3444
- collect(globalComponents);
3445
- collect(pageComponents);
3446
- return { js: jsLibs, css: cssLibs };
3447
- }
3448
- function extractLibraryOrigins(libs) {
3449
- const scriptOrigins = /* @__PURE__ */ new Set();
3450
- const styleOrigins = /* @__PURE__ */ new Set();
3451
- for (const js of libs.js || []) {
3452
- const origin = safeOrigin(js.url);
3453
- if (origin) scriptOrigins.add(origin);
3454
- }
3455
- for (const css of libs.css || []) {
3456
- const origin = safeOrigin(css.url);
3457
- if (origin) styleOrigins.add(origin);
3458
- }
3459
- return { scriptOrigins, styleOrigins };
3460
- }
3461
- function filterLibrariesByContext(libs, context) {
3462
- if (context === "preview") return libs;
3463
- const key = context === "editor" ? "disableEditor" : "disableBuild";
3464
- return {
3465
- js: libs.js,
3466
- css: (libs.css || []).filter((css) => !css[key])
3467
- };
3468
- }
3469
- function safeOrigin(url) {
3470
- if (!url || url.startsWith("/") || url.startsWith("./") || url.startsWith("../")) {
3471
- return null;
3472
- }
3473
- try {
3474
- return new URL(url).origin;
3475
- } catch {
3476
- return null;
3477
- }
3478
- }
3479
-
3480
3558
  // lib/server/ssr/htmlGenerator.ts
3481
3559
  function generateImagePreloadTags(preloadImages) {
3482
3560
  if (preloadImages.length === 0) return "";
3483
- 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 ");
3484
3564
  }
3485
3565
  function minifyCSS(code) {
3486
3566
  if (!code.trim()) return code;
@@ -3528,7 +3608,19 @@ async function generateSSRHTML(pageDataOrOptions, globalComponents = {}, pagePat
3528
3608
  cspNonce
3529
3609
  } = options;
3530
3610
  const nonceAttr = cspNonce ? ` nonce="${cspNonce}"` : "";
3531
- 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
+ );
3532
3624
  let finalClientDataCollections = clientDataCollections;
3533
3625
  if (rendered.neededCollections.size > 0 && cmsServ) {
3534
3626
  finalClientDataCollections = clientDataCollections ? new Map(clientDataCollections) : /* @__PURE__ */ new Map();
@@ -3536,9 +3628,7 @@ async function generateSSRHTML(pageDataOrOptions, globalComponents = {}, pagePat
3536
3628
  if (finalClientDataCollections.has(collectionId)) continue;
3537
3629
  const schema = cmsServ.getSchema(collectionId);
3538
3630
  if (!schema?.clientData?.enabled) {
3539
- console.warn(
3540
- `[SSR] Nested collection "${collectionId}" needs clientData.enabled for client-side hydration`
3541
- );
3631
+ console.warn(`[SSR] Nested collection "${collectionId}" needs clientData.enabled for client-side hydration`);
3542
3632
  continue;
3543
3633
  }
3544
3634
  const items = await cmsServ.queryItems({
@@ -3558,7 +3648,7 @@ async function generateSSRHTML(pageDataOrOptions, globalComponents = {}, pagePat
3558
3648
  await configService.load();
3559
3649
  const globalLibraries = configService.getLibraries() || { js: [], css: [] };
3560
3650
  const globalCustomCode = configService.getCustomCode();
3561
- const menoBadgeHtml = configService.getShowMenoBadge() ? `<style>.meno-badge{position:fixed;bottom:12px;left:12px;z-index:9999;background:#000;color:#fff;padding:4px 10px;border-radius:6px;font-size:12px;font-family:system-ui,sans-serif;text-decoration:none;opacity:0.8;transition:opacity 0.2s}.meno-badge:hover,.meno-badge:focus{opacity:1}</style><a class="meno-badge" href="https://meno.so" target="_blank" rel="noopener">Made in Meno</a>` : "";
3651
+ const menoBadgeHtml = configService.getShowMenoBadge() ? `<style${nonceAttr}>.meno-badge{position:fixed;bottom:12px;left:12px;z-index:9999;background:#000;color:#fff;padding:4px 10px;border-radius:6px;font-size:12px;font-family:system-ui,sans-serif;text-decoration:none;opacity:0.8;transition:opacity 0.2s}.meno-badge:hover,.meno-badge:focus{opacity:1}</style><a class="meno-badge" href="https://meno.so" target="_blank" rel="noopener">Made in Meno</a>` : "";
3562
3652
  const mergedCustomCode = {
3563
3653
  head: [globalCustomCode.head, pageCustomCode?.head].filter(Boolean).join("\n"),
3564
3654
  bodyStart: [globalCustomCode.bodyStart, pageCustomCode?.bodyStart].filter(Boolean).join("\n"),
@@ -3645,8 +3735,18 @@ ${escapedJavaScript}
3645
3735
  const variablesConfig = await variableService.loadConfig();
3646
3736
  const variablesCSS = generateVariablesCSS(variablesConfig, breakpointConfig, responsiveScalesConfig);
3647
3737
  const remConversionConfig = configService.getRemConversion();
3648
- const utilityCSS = generateUtilityCSS(usedUtilityClasses, breakpointConfig, responsiveScalesConfig, remConversionConfig);
3649
- 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
+ ) : "";
3650
3750
  printMissingStyleWarnings(false);
3651
3751
  const baseCSS = `* {
3652
3752
  margin: 0;
@@ -3680,17 +3780,18 @@ picture {
3680
3780
  display: inline-block;
3681
3781
  vertical-align: top;
3682
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;
3683
3791
  }`;
3684
- const combinedCSS = [
3685
- fontCSS,
3686
- themeColorVariablesCSS,
3687
- variablesCSS,
3688
- baseCSS,
3689
- componentCSS,
3690
- utilityCSS,
3691
- interactiveCSS
3692
- ].filter(Boolean).join("\n");
3693
- const finalCSS = useBundled ? minifyCSS(combinedCSS) : combinedCSS;
3792
+ const combinedCSS = [fontCSS, themeColorVariablesCSS, variablesCSS, baseCSS, componentCSS, utilityCSS, interactiveCSS].filter(Boolean).join("\n");
3793
+ const cssWithStableViewport = rewriteViewportUnits(combinedCSS);
3794
+ const finalCSS = useBundled ? minifyCSS(cssWithStableViewport) : cssWithStableViewport;
3694
3795
  const prefetchConfig = await loadPrefetchConfig();
3695
3796
  const menoConfig = prefetchConfig.enabled ? { prefetch: prefetchConfig } : {};
3696
3797
  const hasConfig = Object.keys(menoConfig).length > 0;
@@ -3712,7 +3813,7 @@ picture {
3712
3813
  const scriptPreloadTag = extScriptPath ? `<link rel="preload" href="${extScriptPath}" as="script">` : "";
3713
3814
  const imagePreloadTags = generateImagePreloadTags(rendered.preloadImages);
3714
3815
  const wsUrl = serverPort ? `'ws://localhost:${serverPort}/hmr'` : `location.origin.replace('http','ws')+'/hmr'`;
3715
- const liveReloadScript = injectLiveReload ? `<script${nonceAttr}>(function(){var ws,timer,gen=0,lastSrvRoot=null;function strip(s){return s?s.replace(/[?&]_r=\\d+/,''):''}function classList(el){return (el.getAttribute('class')||'').split(/\\s+/).filter(Boolean)}function syncEl(cur,srv,old){var cc=classList(cur),sc=classList(srv),oc=old?new Set(classList(old)):new Set();var rt=cc.filter(function(c){return !oc.has(c)});var seen=new Set(),fin=[];sc.concat(rt).forEach(function(c){if(!seen.has(c)){seen.add(c);fin.push(c)}});var fs=fin.join(' ');if((cur.getAttribute('class')||'')!==fs){if(fs)cur.setAttribute('class',fs);else cur.removeAttribute('class')}for(var i=0;i<srv.attributes.length;i++){var a=srv.attributes[i];if(a.name==='class')continue;if(cur.getAttribute(a.name)!==a.value)cur.setAttribute(a.name,a.value)}if(old){for(var i=0;i<old.attributes.length;i++){var a=old.attributes[i];if(a.name==='class')continue;if(!srv.hasAttribute(a.name)&&cur.hasAttribute(a.name))cur.removeAttribute(a.name)}}}function syncText(cur,srv){var cc=cur.childNodes,sc=srv.childNodes;for(var i=0;i<sc.length;i++){var s=sc[i],c=cc[i];if(s.nodeType===3&&c&&c.nodeType===3){if(c.textContent!==s.textContent)c.textContent=s.textContent}}}function smartUpdate(curR,srvR,oldR){var ce=curR.querySelectorAll('[data-element-path]'),se=srvR.querySelectorAll('[data-element-path]');if(ce.length!==se.length){if(curR.innerHTML!==srvR.innerHTML)curR.innerHTML=srvR.innerHTML;return}var sbp={};for(var i=0;i<se.length;i++)sbp[se[i].getAttribute('data-element-path')]=se[i];var obp={};if(oldR){var oe=oldR.querySelectorAll('[data-element-path]');for(var i=0;i<oe.length;i++)obp[oe[i].getAttribute('data-element-path')]=oe[i]}for(var i=0;i<ce.length;i++){var c=ce[i],p=c.getAttribute('data-element-path'),s=sbp[p];if(!s){if(curR.innerHTML!==srvR.innerHTML)curR.innerHTML=srvR.innerHTML;return}syncEl(c,s,obp[p]);syncText(c,s)}syncText(curR,srvR)}function connect(){ws=new WebSocket(${wsUrl});ws.onmessage=function(e){var d=JSON.parse(e.data);if(d.type==='hmr:libraries-update'){location.reload()}else if(d.type==='hmr:update'||d.type==='hmr:cms-update'||d.type==='hmr:colors-update'||d.type==='hmr:variables-update')hotReload()};ws.onclose=function(){clearTimeout(timer);timer=setTimeout(connect,1000)}}function hotReload(){var g=++gen;var sx=window.scrollX,sy=window.scrollY;fetch(location.href,{cache:'no-store'}).then(function(r){return r.text()}).then(function(html){if(g!==gen)return;var p=new DOMParser();var d=p.parseFromString(html,'text/html');var or=document.getElementById('root'),nr=d.getElementById('root');if(or&&nr)smartUpdate(or,nr,lastSrvRoot);if(nr)lastSrvRoot=nr.cloneNode(true);var os=document.getElementById('meno-styles'),ns=d.getElementById('meno-styles');if(os&&ns&&os.textContent!==ns.textContent)os.parentNode.replaceChild(ns.cloneNode(true),os);var nh=d.documentElement;if(nh){var nl=nh.getAttribute('lang')||'en',nt=nh.getAttribute('theme')||'light';if(document.documentElement.getAttribute('lang')!==nl)document.documentElement.setAttribute('lang',nl);if(document.documentElement.getAttribute('theme')!==nt)document.documentElement.setAttribute('theme',nt)}var ocms=document.querySelectorAll('script[id^="meno-cms-"]'),ncms=d.querySelectorAll('script[id^="meno-cms-"]');var ock=JSON.stringify(Array.prototype.map.call(ocms,function(s){return [s.id,s.textContent]}));var nck=JSON.stringify(Array.prototype.map.call(ncms,function(s){return [s.id,s.textContent]}));if(ock!==nck){ocms.forEach(function(s){s.remove()});ncms.forEach(function(s){var c=document.createElement('script');c.type=s.type;c.id=s.id;c.textContent=s.textContent;document.head.appendChild(c)})}window.__menoHotReload=true;var olib=document.querySelectorAll('body > script[src^="/libraries/"]'),nlib=d.querySelectorAll('body > script[src^="/libraries/"]');var olk=JSON.stringify(Array.prototype.map.call(olib,function(s){return strip(s.getAttribute('src'))}).sort());var nlk=JSON.stringify(Array.prototype.map.call(nlib,function(s){return strip(s.getAttribute('src'))}).sort());if(olk!==nlk){olib.forEach(function(o){o.remove()});nlib.forEach(function(n){var src=n.getAttribute('src');var ls=document.createElement('script');ls.src=src+(src.indexOf('?')>-1?'&':'?')+'_r='+Date.now();document.body.appendChild(ls)})}var oscr=document.querySelector('script[src^="/_scripts/"]'),nscr=d.querySelector('script[src^="/_scripts/"]');var oss=oscr?strip(oscr.getAttribute('src')):'',nss=nscr?strip(nscr.getAttribute('src')):'';if(oss===nss){window.scrollTo(sx,sy)}else{if(oscr)oscr.remove();if(nscr){var src=nscr.getAttribute('src');var s=document.createElement('script');s.src=src+(src.indexOf('?')>-1?'&':'?')+'_r='+Date.now();s.onload=function(){document.dispatchEvent(new Event('DOMContentLoaded'));window.scrollTo(sx,sy)};s.onerror=function(){window.scrollTo(sx,sy)};document.body.appendChild(s)}else{document.dispatchEvent(new Event('DOMContentLoaded'));window.scrollTo(sx,sy)}}}).catch(function(){location.reload()})}var iR=document.getElementById('root');if(iR)lastSrvRoot=iR.cloneNode(true);connect()})()</script>` : "";
3816
+ const liveReloadScript = injectLiveReload ? `<script${nonceAttr}>(function(){var ws,timer,gen=0,lastSrvRoot=null,dn=document.querySelector('meta[name="csp-nonce"]'),docNonce=dn?dn.getAttribute('content'):'';function strip(s){return s?s.replace(/[?&]_r=\\d+/,''):''}function classList(el){return (el.getAttribute('class')||'').split(/\\s+/).filter(Boolean)}function syncEl(cur,srv,old){var cc=classList(cur),sc=classList(srv),oc=old?new Set(classList(old)):new Set();var rt=cc.filter(function(c){return !oc.has(c)});var seen=new Set(),fin=[];sc.concat(rt).forEach(function(c){if(!seen.has(c)){seen.add(c);fin.push(c)}});var fs=fin.join(' ');if((cur.getAttribute('class')||'')!==fs){if(fs)cur.setAttribute('class',fs);else cur.removeAttribute('class')}for(var i=0;i<srv.attributes.length;i++){var a=srv.attributes[i];if(a.name==='class')continue;var ov=old?old.getAttribute(a.name):null;if(a.value!==ov){if(cur.getAttribute(a.name)!==a.value)cur.setAttribute(a.name,a.value)}}if(old){for(var i=0;i<old.attributes.length;i++){var a=old.attributes[i];if(a.name==='class')continue;if(!srv.hasAttribute(a.name)&&cur.hasAttribute(a.name))cur.removeAttribute(a.name)}}}function syncText(cur,srv){var cc=cur.childNodes,sc=srv.childNodes;for(var i=0;i<sc.length;i++){var s=sc[i],c=cc[i];if(s.nodeType===3&&c&&c.nodeType===3){if(c.textContent!==s.textContent)c.textContent=s.textContent}}}function ek(el){var p=el.getAttribute('data-element-path'),ci=el.getAttribute('data-cms-item-index');return ci?p+'|'+ci:p}function structKey(root){var e=root.querySelectorAll('[data-element-path]'),k=[];for(var i=0;i<e.length;i++)k.push(ek(e[i]));return k.sort().join('~')}function softSync(curR,srvR,oldR){var ce=curR.querySelectorAll('[data-element-path]');var sbp={},se=srvR.querySelectorAll('[data-element-path]');for(var i=0;i<se.length;i++)sbp[ek(se[i])]=se[i];var obp={};if(oldR){var oe=oldR.querySelectorAll('[data-element-path]');for(var i=0;i<oe.length;i++)obp[ek(oe[i])]=oe[i]}for(var i=0;i<ce.length;i++){var c=ce[i],p=ek(c),s=sbp[p];if(!s)continue;syncEl(c,s,obp[p]);syncText(c,s)}syncText(curR,srvR)}function connect(){ws=new WebSocket(${wsUrl});ws.onmessage=function(e){var d=JSON.parse(e.data);if(d.type==='hmr:libraries-update'){location.reload()}else if(d.type==='hmr:update'||d.type==='hmr:cms-update'||d.type==='hmr:colors-update'||d.type==='hmr:variables-update')hotReload()};ws.onclose=function(){clearTimeout(timer);timer=setTimeout(connect,1000)}}function hotReload(){var g=++gen;var sx=window.scrollX,sy=window.scrollY;fetch(location.href,{cache:'no-store'}).then(function(r){return r.text()}).then(function(html){if(g!==gen)return;var p=new DOMParser();var d=p.parseFromString(html,'text/html');var or=document.getElementById('root'),nr=d.getElementById('root');var oscr=document.querySelector('script[src^="/_scripts/"]'),nscr=d.querySelector('script[src^="/_scripts/"]');var oss=oscr?strip(oscr.getAttribute('src')):'',nss=nscr?strip(nscr.getAttribute('src')):'';var hardReset=(oss!==nss)||!lastSrvRoot||!or||!nr||structKey(lastSrvRoot)!==structKey(nr);if(or&&nr){if(hardReset){if(or.innerHTML!==nr.innerHTML)or.innerHTML=nr.innerHTML}else{softSync(or,nr,lastSrvRoot)}}if(nr)lastSrvRoot=nr.cloneNode(true);var os=document.getElementById('meno-styles'),ns=d.getElementById('meno-styles');if(os&&ns&&os.textContent!==ns.textContent)os.textContent=ns.textContent;var nh=d.documentElement;if(nh){var nl=nh.getAttribute('lang')||'en',nt=nh.getAttribute('theme')||'light';if(document.documentElement.getAttribute('lang')!==nl)document.documentElement.setAttribute('lang',nl);if(document.documentElement.getAttribute('theme')!==nt)document.documentElement.setAttribute('theme',nt)}var ocms=document.querySelectorAll('script[id^="meno-cms-"]'),ncms=d.querySelectorAll('script[id^="meno-cms-"]');var ock=JSON.stringify(Array.prototype.map.call(ocms,function(s){return [s.id,s.textContent]}));var nck=JSON.stringify(Array.prototype.map.call(ncms,function(s){return [s.id,s.textContent]}));if(ock!==nck){ocms.forEach(function(s){s.remove()});ncms.forEach(function(s){var c=document.createElement('script');c.type=s.type;c.id=s.id;if(docNonce)c.nonce=docNonce;c.textContent=s.textContent;document.head.appendChild(c)})}window.__menoHotReload=true;var olib=document.querySelectorAll('body > script[src^="/libraries/"]'),nlib=d.querySelectorAll('body > script[src^="/libraries/"]');var olk=JSON.stringify(Array.prototype.map.call(olib,function(s){return strip(s.getAttribute('src'))}).sort());var nlk=JSON.stringify(Array.prototype.map.call(nlib,function(s){return strip(s.getAttribute('src'))}).sort());if(olk!==nlk){olib.forEach(function(o){o.remove()});nlib.forEach(function(n){var src=n.getAttribute('src');var ls=document.createElement('script');ls.src=src+(src.indexOf('?')>-1?'&':'?')+'_r='+Date.now();document.body.appendChild(ls)})}if(!hardReset){window.scrollTo(sx,sy)}else{if(oscr)oscr.remove();if(nscr){var src=nscr.getAttribute('src');var s=document.createElement('script');s.src=src+(src.indexOf('?')>-1?'&':'?')+'_r='+Date.now();s.onload=function(){document.dispatchEvent(new Event('DOMContentLoaded'));window.scrollTo(sx,sy)};s.onerror=function(){window.scrollTo(sx,sy)};document.body.appendChild(s)}else{document.dispatchEvent(new Event('DOMContentLoaded'));window.scrollTo(sx,sy)}}}).catch(function(){location.reload()})}var iR=document.getElementById('root');if(iR)lastSrvRoot=iR.cloneNode(true);connect()})()</script>` : "";
3716
3817
  const scrollHandlerScript = injectLiveReload ? `<script${nonceAttr}>(function(){window.addEventListener('message',function(e){if(e.data.type==='GET_SCROLL_POSITION'){window.parent.postMessage({type:'SCROLL_POSITION_RESPONSE',scrollX:window.scrollX,scrollY:window.scrollY},'*')}else if(e.data.type==='SET_SCROLL_POSITION'){window.scrollTo(e.data.scrollX,e.data.scrollY)}})})()</script>` : "";
3717
3818
  const styleContent = useBundled ? finalCSS : `
3718
3819
  ${combinedCSS.split("\n").join("\n ")}
@@ -3722,8 +3823,9 @@ picture {
3722
3823
  <head>
3723
3824
  <meta charset="UTF-8">
3724
3825
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
3725
- ${iconTags ? iconTags + "\n " : ""}${scriptPreloadTag ? scriptPreloadTag + "\n " : ""}${imagePreloadTags ? imagePreloadTags + "\n " : ""}${fontPreloadTags ? fontPreloadTags + "\n " : ""}${libraryTags.headCSS ? libraryTags.headCSS + "\n " : ""}${libraryTags.headJS ? libraryTags.headJS + "\n " : ""}${rendered.meta}
3726
- ${configInlineScript}${cmsInlineScript}${clientDataScripts}<style id="meno-styles">${styleContent}</style>${mergedCustomCode.head ? "\n " + mergedCustomCode.head : ""}
3826
+ ${cspNonce ? `<meta name="csp-nonce" content="${cspNonce}">
3827
+ ` : ""}${iconTags ? iconTags + "\n " : ""}${scriptPreloadTag ? scriptPreloadTag + "\n " : ""}${imagePreloadTags ? imagePreloadTags + "\n " : ""}${fontPreloadTags ? fontPreloadTags + "\n " : ""}${libraryTags.headCSS ? libraryTags.headCSS + "\n " : ""}${libraryTags.headJS ? libraryTags.headJS + "\n " : ""}${rendered.meta}
3828
+ ${configInlineScript}${cmsInlineScript}${clientDataScripts}<style id="meno-styles"${nonceAttr}>${styleContent}</style>${mergedCustomCode.head ? "\n " + mergedCustomCode.head : ""}
3727
3829
  </head>
3728
3830
  <body>${mergedCustomCode.bodyStart ? "\n " + mergedCustomCode.bodyStart : ""}
3729
3831
  <div id="root">
@@ -4605,9 +4707,7 @@ var MenoFilter = class _MenoFilter {
4605
4707
  result = result.filter((item) => this.matchesCriteria(item, this.criteria));
4606
4708
  }
4607
4709
  if (this.orCriteria.length > 0) {
4608
- result = result.filter(
4609
- (item) => this.orCriteria.some((criteria) => this.matchesCriteria(item, criteria))
4610
- );
4710
+ result = result.filter((item) => this.orCriteria.some((criteria) => this.matchesCriteria(item, criteria)));
4611
4711
  }
4612
4712
  if (this.searchQuery) {
4613
4713
  const query = this.searchQuery;
@@ -4721,9 +4821,10 @@ var MenoFilter = class _MenoFilter {
4721
4821
  return Array.isArray(opValue) ? opValue.includes(itemValue) : false;
4722
4822
  case "$nin":
4723
4823
  return Array.isArray(opValue) ? !opValue.includes(itemValue) : true;
4724
- case "$empty":
4824
+ case "$empty": {
4725
4825
  const isEmpty = itemValue === void 0 || itemValue === null || itemValue === "" || Array.isArray(itemValue) && itemValue.length === 0;
4726
4826
  return opValue ? isEmpty : !isEmpty;
4827
+ }
4727
4828
  default:
4728
4829
  console.warn(`MenoFilter: Unknown operator "${op}"`);
4729
4830
  return true;
@@ -4829,9 +4930,7 @@ function handleMultiButtonClick(filter, field, value, currentValue) {
4829
4930
  }
4830
4931
  function bindFilterControls(instance) {
4831
4932
  const { wrapper, filter, cleanup } = instance;
4832
- const filterButtons = wrapper.querySelectorAll(
4833
- `[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`
4834
- );
4933
+ const filterButtons = wrapper.querySelectorAll(`[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`);
4835
4934
  for (const btn of filterButtons) {
4836
4935
  if (btn.tagName === "INPUT") continue;
4837
4936
  const field = btn.getAttribute(ATTR.FILTER_FIELD);
@@ -4857,9 +4956,7 @@ function bindFilterControls(instance) {
4857
4956
  btn.addEventListener("click", handler);
4858
4957
  cleanup.push(() => btn.removeEventListener("click", handler));
4859
4958
  }
4860
- const filterCheckboxes = wrapper.querySelectorAll(
4861
- `input[type="checkbox"][${ATTR.FILTER_FIELD}]`
4862
- );
4959
+ const filterCheckboxes = wrapper.querySelectorAll(`input[type="checkbox"][${ATTR.FILTER_FIELD}]`);
4863
4960
  for (const checkbox of filterCheckboxes) {
4864
4961
  const field = checkbox.getAttribute(ATTR.FILTER_FIELD);
4865
4962
  const handler = () => {
@@ -4879,9 +4976,7 @@ function bindFilterControls(instance) {
4879
4976
  checkbox.addEventListener("change", handler);
4880
4977
  cleanup.push(() => checkbox.removeEventListener("change", handler));
4881
4978
  }
4882
- const filterSelects = wrapper.querySelectorAll(
4883
- `select[${ATTR.FILTER_FIELD}]`
4884
- );
4979
+ const filterSelects = wrapper.querySelectorAll(`select[${ATTR.FILTER_FIELD}]`);
4885
4980
  for (const select of filterSelects) {
4886
4981
  const field = select.getAttribute(ATTR.FILTER_FIELD);
4887
4982
  const handler = () => {
@@ -4895,9 +4990,7 @@ function bindFilterControls(instance) {
4895
4990
  select.addEventListener("change", handler);
4896
4991
  cleanup.push(() => select.removeEventListener("change", handler));
4897
4992
  }
4898
- const filterRadios = wrapper.querySelectorAll(
4899
- `input[type="radio"][${ATTR.FILTER_FIELD}]`
4900
- );
4993
+ const filterRadios = wrapper.querySelectorAll(`input[type="radio"][${ATTR.FILTER_FIELD}]`);
4901
4994
  for (const radio of filterRadios) {
4902
4995
  const field = radio.getAttribute(ATTR.FILTER_FIELD);
4903
4996
  const value = radio.getAttribute(ATTR.FILTER_VALUE) || radio.value;
@@ -4918,9 +5011,7 @@ function updateCheckboxFilters(wrapper, filter, field) {
4918
5011
  const checkboxes = wrapper.querySelectorAll(
4919
5012
  `input[type="checkbox"][${ATTR.FILTER_FIELD}="${field}"]:checked`
4920
5013
  );
4921
- const values = Array.from(checkboxes).map(
4922
- (cb) => cb.getAttribute(ATTR.FILTER_VALUE) || cb.value
4923
- );
5014
+ const values = Array.from(checkboxes).map((cb) => cb.getAttribute(ATTR.FILTER_VALUE) || cb.value);
4924
5015
  if (values.length === 0) {
4925
5016
  filter.removeFilter(field);
4926
5017
  } else if (values.length === 1) {
@@ -5008,15 +5099,11 @@ function bindActionControls(instance) {
5008
5099
  }
5009
5100
  }
5010
5101
  function resetFormControls(wrapper) {
5011
- const checkboxes = wrapper.querySelectorAll(
5012
- `input[type="checkbox"][${ATTR.FILTER_FIELD}]`
5013
- );
5102
+ const checkboxes = wrapper.querySelectorAll(`input[type="checkbox"][${ATTR.FILTER_FIELD}]`);
5014
5103
  for (const cb of checkboxes) {
5015
5104
  cb.checked = false;
5016
5105
  }
5017
- const selects = wrapper.querySelectorAll(
5018
- `select[${ATTR.FILTER_FIELD}]`
5019
- );
5106
+ const selects = wrapper.querySelectorAll(`select[${ATTR.FILTER_FIELD}]`);
5020
5107
  for (const select of selects) {
5021
5108
  select.selectedIndex = 0;
5022
5109
  }
@@ -5048,19 +5135,18 @@ function bindPaginationControls(instance) {
5048
5135
  case "last":
5049
5136
  filter.setPage(filter.getPageInfo().total);
5050
5137
  break;
5051
- default:
5138
+ default: {
5052
5139
  const page = parseInt(action || "1", 10);
5053
5140
  if (!isNaN(page)) {
5054
5141
  filter.setPage(page);
5055
5142
  }
5143
+ }
5056
5144
  }
5057
5145
  };
5058
5146
  btn.addEventListener("click", handler);
5059
5147
  cleanup.push(() => btn.removeEventListener("click", handler));
5060
5148
  }
5061
- const perPageSelects = wrapper.querySelectorAll(
5062
- `[${ATTR.PER_PAGE_SELECT}]`
5063
- );
5149
+ const perPageSelects = wrapper.querySelectorAll(`[${ATTR.PER_PAGE_SELECT}]`);
5064
5150
  for (const select of perPageSelects) {
5065
5151
  const handler = () => {
5066
5152
  const perPage = parseInt(select.value, 10);
@@ -5208,9 +5294,7 @@ function renderNestedItemFromTemplate(template, item, itemAs, index, total, pare
5208
5294
  return element;
5209
5295
  }
5210
5296
  function hydrateNestedCMSLists(element, parentItem, parentItemAs) {
5211
- const placeholders = element.querySelectorAll(
5212
- '[data-cms-list-nested="true"]'
5213
- );
5297
+ const placeholders = element.querySelectorAll('[data-cms-list-nested="true"]');
5214
5298
  for (const placeholder of placeholders) {
5215
5299
  hydrateNestedCMSList(placeholder, parentItem, parentItemAs);
5216
5300
  }
@@ -5225,15 +5309,15 @@ function hydrateNestedCMSList(placeholder, parentItem, parentItemAs) {
5225
5309
  return;
5226
5310
  }
5227
5311
  const collection = config.collection;
5228
- const templateEl = placeholder.querySelector(
5229
- "template[data-nested-template]"
5230
- );
5312
+ const templateEl = placeholder.querySelector("template[data-nested-template]");
5231
5313
  if (!templateEl) return;
5232
5314
  const childTemplate = templateEl.innerHTML.trim();
5233
5315
  const nestedItemAs = config.itemAs || singularizeWord(collection);
5234
5316
  const collectionData = getCollectionData(collection);
5235
5317
  if (!collectionData) {
5236
- 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
+ );
5237
5321
  return;
5238
5322
  }
5239
5323
  let items;
@@ -5440,7 +5524,7 @@ function filterDOMOnly(instance, listEl) {
5440
5524
  const sortConfig = filter.getSort();
5441
5525
  const perPage = filter.getPageInfo().perPage;
5442
5526
  const currentPage = filter.getPageInfo().current;
5443
- let filteredItems = items.filter((item) => {
5527
+ const filteredItems = items.filter((item) => {
5444
5528
  for (const [field, value] of Object.entries(filters)) {
5445
5529
  const itemValue = getItemFieldValue(item, field);
5446
5530
  if (!matchesFilter(itemValue, value)) {
@@ -5569,9 +5653,7 @@ function updateFacets(wrapper, filter) {
5569
5653
  function updateActiveFilters(wrapper, filter, instance) {
5570
5654
  const container = wrapper.querySelector(`[${ATTR.ACTIVE_FILTERS}]`);
5571
5655
  if (!container) return;
5572
- const template = wrapper.querySelector(
5573
- `template[${ATTR.ACTIVE_FILTER_TEMPLATE}]`
5574
- );
5656
+ const template = wrapper.querySelector(`template[${ATTR.ACTIVE_FILTER_TEMPLATE}]`);
5575
5657
  const filters = filter.getFilters();
5576
5658
  const entries = Object.entries(filters);
5577
5659
  container.innerHTML = "";
@@ -5702,9 +5784,7 @@ function updateLoadMoreUI(wrapper, filter) {
5702
5784
  function updateActiveStates(wrapper, filter) {
5703
5785
  const filters = filter.getFilters();
5704
5786
  const activeClass = wrapper.getAttribute(ATTR.ACTIVE_CLASS) || "active";
5705
- const filterButtons = wrapper.querySelectorAll(
5706
- `[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`
5707
- );
5787
+ const filterButtons = wrapper.querySelectorAll(`[${ATTR.FILTER_FIELD}][${ATTR.FILTER_VALUE}]`);
5708
5788
  for (const btn of filterButtons) {
5709
5789
  if (btn.tagName === "INPUT") continue;
5710
5790
  const field = btn.getAttribute(ATTR.FILTER_FIELD);
@@ -5937,7 +6017,9 @@ var FileSystemCMSProvider = class {
5937
6017
  */
5938
6018
  validateCollection(collection) {
5939
6019
  if (!isValidIdentifier(collection)) {
5940
- 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
+ );
5941
6023
  }
5942
6024
  }
5943
6025
  /**
@@ -5946,7 +6028,9 @@ var FileSystemCMSProvider = class {
5946
6028
  */
5947
6029
  validateFilename(filename) {
5948
6030
  if (!isSafePathSegment(filename)) {
5949
- 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
+ );
5950
6034
  }
5951
6035
  if (isReservedDraftFilename(filename)) {
5952
6036
  throw new Error(`Invalid filename: "${filename}". The "${CMS_DRAFT_SUFFIX}" suffix is reserved for draft files.`);
@@ -6271,7 +6355,9 @@ var FileSystemCMSProvider = class {
6271
6355
  */
6272
6356
  async saveSchema(collectionId, pageData) {
6273
6357
  if (!isValidIdentifier(collectionId)) {
6274
- 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
+ );
6275
6361
  }
6276
6362
  const { writeFile: writeFile2, mkdir } = await import("fs/promises");
6277
6363
  if (!existsSync2(this.templatesDir)) {
@@ -6294,7 +6380,9 @@ var FileSystemCMSProvider = class {
6294
6380
  */
6295
6381
  async updateSchema(collectionId, updates) {
6296
6382
  if (!isValidIdentifier(collectionId)) {
6297
- 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
+ );
6298
6386
  }
6299
6387
  const { readFile, writeFile: writeFile2 } = await import("fs/promises");
6300
6388
  const pageFilePath = join2(this.templatesDir, `${collectionId}.json`);
@@ -6348,10 +6436,6 @@ export {
6348
6436
  generateFontPreloadTags,
6349
6437
  generateThemeColorVariablesCSS,
6350
6438
  generateVariablesCSS,
6351
- buildSlugIndex,
6352
- translatePath,
6353
- getLocaleLinks,
6354
- resolveSlugToPageId,
6355
6439
  escapeHtml,
6356
6440
  buildAttributes,
6357
6441
  styleToString,
@@ -6374,13 +6458,8 @@ export {
6374
6458
  menoFilterScript,
6375
6459
  needsMenoFilter,
6376
6460
  prepareClientData,
6377
- mergeLibraries,
6378
- generateLibraryTags,
6379
- collectComponentLibraries,
6380
- extractLibraryOrigins,
6381
- filterLibrariesByContext,
6382
6461
  generateSSRHTML,
6383
6462
  FileSystemCMSProvider,
6384
6463
  migrateTemplatesDirectory
6385
6464
  };
6386
- //# sourceMappingURL=chunk-CXCBV2M7.js.map
6465
+ //# sourceMappingURL=chunk-2FN4UOVO.js.map