meno-core 1.0.53 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (415) hide show
  1. package/.claude/settings.local.json +1 -3
  2. package/bin/cli.ts +66 -261
  3. package/build-astro.ts +150 -128
  4. package/dist/bin/cli.js +42 -185
  5. package/dist/bin/cli.js.map +2 -2
  6. package/dist/chunks/chunk-2AR55GYH.js +42 -0
  7. package/dist/chunks/chunk-2AR55GYH.js.map +7 -0
  8. package/dist/chunks/{chunk-JGWFTO6P.js → chunk-2IIQK7T3.js} +2624 -1389
  9. package/dist/chunks/chunk-2IIQK7T3.js.map +7 -0
  10. package/dist/chunks/chunk-4ZRU52J2.js +169 -0
  11. package/dist/chunks/chunk-4ZRU52J2.js.map +7 -0
  12. package/dist/chunks/{chunk-UB44F4Z2.js → chunk-5X4HCN7J.js} +5 -7
  13. package/dist/chunks/chunk-5X4HCN7J.js.map +7 -0
  14. package/dist/chunks/{chunk-WQFG7PAH.js → chunk-7CCVOL5M.js} +15 -19
  15. package/dist/chunks/chunk-7CCVOL5M.js.map +7 -0
  16. package/dist/chunks/{chunk-YBLHKYFF.js → chunk-AR7LHIFY.js} +8 -2
  17. package/dist/chunks/chunk-AR7LHIFY.js.map +7 -0
  18. package/dist/chunks/{chunk-O3NAGJP4.js → chunk-NUP7H7D3.js} +135 -41
  19. package/dist/chunks/chunk-NUP7H7D3.js.map +7 -0
  20. package/dist/chunks/{chunk-X754AHS5.js → chunk-QWTQZHG3.js} +194 -90
  21. package/dist/chunks/chunk-QWTQZHG3.js.map +7 -0
  22. package/dist/chunks/{chunk-H3GJ4H2U.js → chunk-XTKNX4FW.js} +216 -87
  23. package/dist/chunks/chunk-XTKNX4FW.js.map +7 -0
  24. package/dist/chunks/{fs-JGINUXGL.js → fs-G3ANWEFP.js} +2 -2
  25. package/dist/lib/client/index.js +1003 -475
  26. package/dist/lib/client/index.js.map +3 -3
  27. package/dist/lib/server/index.js +14393 -6371
  28. package/dist/lib/server/index.js.map +4 -4
  29. package/dist/lib/shared/index.js +342 -101
  30. package/dist/lib/shared/index.js.map +4 -4
  31. package/dist/lib/shared/richtext/index.js +1 -1
  32. package/dist/lib/test-utils/index.js +64 -80
  33. package/dist/lib/test-utils/index.js.map +2 -2
  34. package/entries/client-router.tsx +10 -8
  35. package/lib/client/ClientInitializer.ts +8 -8
  36. package/lib/client/ErrorBoundary.test.tsx +246 -186
  37. package/lib/client/ErrorBoundary.tsx +183 -132
  38. package/lib/client/componentRegistry.test.ts +96 -108
  39. package/lib/client/componentRegistry.ts +1 -3
  40. package/lib/client/contexts/ThemeContext.tsx +3 -2
  41. package/lib/client/core/ComponentBuilder.test.ts +663 -560
  42. package/lib/client/core/ComponentBuilder.ts +427 -155
  43. package/lib/client/core/ComponentRenderer.test.tsx +2 -4
  44. package/lib/client/core/ComponentRenderer.tsx +46 -33
  45. package/lib/client/core/builders/embedBuilder.ts +242 -54
  46. package/lib/client/core/builders/linkBuilder.ts +72 -45
  47. package/lib/client/core/builders/linkNodeBuilder.ts +79 -54
  48. package/lib/client/core/builders/listBuilder.ts +155 -89
  49. package/lib/client/core/builders/localeListBuilder.ts +97 -62
  50. package/lib/client/core/builders/types.ts +5 -5
  51. package/lib/client/core/cmsTemplateProcessor.ts +8 -9
  52. package/lib/client/elementRegistry.ts +3 -3
  53. package/lib/client/fontFamiliesService.test.ts +2 -10
  54. package/lib/client/fontFamiliesService.ts +3 -3
  55. package/lib/client/hmr/HMRManager.tsx +47 -30
  56. package/lib/client/hmrCssReload.ts +49 -14
  57. package/lib/client/hmrWebSocket.ts +14 -19
  58. package/lib/client/hooks/useColorVariables.test.ts +21 -21
  59. package/lib/client/hooks/useColorVariables.ts +23 -18
  60. package/lib/client/hooks/usePropertyAutocomplete.ts +4 -6
  61. package/lib/client/hooks/useVariables.ts +6 -4
  62. package/lib/client/hydration/HydrationUtils.test.ts +24 -25
  63. package/lib/client/hydration/HydrationUtils.ts +3 -4
  64. package/lib/client/i18nConfigService.test.ts +2 -7
  65. package/lib/client/i18nConfigService.ts +2 -2
  66. package/lib/client/meno-filter/MenoFilter.test.ts +47 -49
  67. package/lib/client/meno-filter/MenoFilter.ts +14 -15
  68. package/lib/client/meno-filter/bindings.ts +18 -43
  69. package/lib/client/meno-filter/init.ts +4 -4
  70. package/lib/client/meno-filter/renderer.ts +30 -32
  71. package/lib/client/meno-filter/script.generated.ts +1 -3
  72. package/lib/client/meno-filter/ui.ts +4 -6
  73. package/lib/client/meno-filter/updates.ts +18 -23
  74. package/lib/client/meno-filter/utils.ts +1 -1
  75. package/lib/client/navigation.test.ts +174 -178
  76. package/lib/client/navigation.ts +0 -1
  77. package/lib/client/responsiveStyleResolver.knownTokens.test.ts +71 -0
  78. package/lib/client/responsiveStyleResolver.test.ts +234 -232
  79. package/lib/client/responsiveStyleResolver.ts +74 -20
  80. package/lib/client/routing/RouteLoader.test.ts +24 -25
  81. package/lib/client/routing/RouteLoader.ts +27 -35
  82. package/lib/client/routing/Router.tsx +210 -153
  83. package/lib/client/scripts/ScriptExecutor.test.ts +157 -158
  84. package/lib/client/scripts/ScriptExecutor.ts +18 -36
  85. package/lib/client/services/PrefetchService.test.ts +3 -3
  86. package/lib/client/services/PrefetchService.ts +23 -29
  87. package/lib/client/styleProcessor.test.ts +9 -9
  88. package/lib/client/styleProcessor.ts +24 -15
  89. package/lib/client/styles/StyleInjector.test.ts +122 -115
  90. package/lib/client/styles/StyleInjector.ts +10 -7
  91. package/lib/client/styles/UtilityClassCollector.ts +62 -28
  92. package/lib/client/styles/cspNonce.test.ts +2 -5
  93. package/lib/client/templateEngine.test.ts +554 -488
  94. package/lib/client/templateEngine.ts +203 -73
  95. package/lib/client/theme.test.ts +1 -1
  96. package/lib/client/theme.ts +0 -1
  97. package/lib/client/utils/toast.ts +0 -1
  98. package/lib/server/__integration__/api-routes.test.ts +8 -4
  99. package/lib/server/__integration__/cms-integration.test.ts +1 -4
  100. package/lib/server/__integration__/server-lifecycle.test.ts +4 -5
  101. package/lib/server/__integration__/ssr-rendering.test.ts +47 -37
  102. package/lib/server/__integration__/static-assets.test.ts +3 -3
  103. package/lib/server/__integration__/test-helpers.ts +87 -74
  104. package/lib/server/ab/generateFunctions.ts +12 -10
  105. package/lib/server/astro/cmsPageEmitter.ts +26 -42
  106. package/lib/server/astro/componentEmitter.ts +35 -43
  107. package/lib/server/astro/cssCollector.ts +10 -26
  108. package/lib/server/astro/nodeToAstro.test.ts +1754 -34
  109. package/lib/server/astro/nodeToAstro.ts +232 -216
  110. package/lib/server/astro/normalizeOrphanTemplateProps.test.ts +115 -119
  111. package/lib/server/astro/normalizeOrphanTemplateProps.ts +11 -18
  112. package/lib/server/astro/pageEmitter.ts +9 -13
  113. package/lib/server/astro/tailwindMapper.test.ts +10 -37
  114. package/lib/server/astro/tailwindMapper.ts +33 -40
  115. package/lib/server/astro/templateTransformer.ts +17 -20
  116. package/lib/server/createServer.ts +7 -19
  117. package/lib/server/cssGenerator.test.ts +35 -44
  118. package/lib/server/cssGenerator.ts +8 -19
  119. package/lib/server/fileWatcher.test.ts +164 -13
  120. package/lib/server/fileWatcher.ts +209 -124
  121. package/lib/server/index.ts +14 -17
  122. package/lib/server/jsonLoader.test.ts +39 -2
  123. package/lib/server/jsonLoader.ts +39 -34
  124. package/lib/server/middleware/cors.test.ts +21 -21
  125. package/lib/server/middleware/cors.ts +28 -4
  126. package/lib/server/middleware/errorHandler.test.ts +7 -5
  127. package/lib/server/middleware/errorHandler.ts +3 -8
  128. package/lib/server/middleware/index.ts +0 -1
  129. package/lib/server/middleware/logger.test.ts +10 -8
  130. package/lib/server/middleware/logger.ts +17 -29
  131. package/lib/server/migrateTemplates.ts +3 -3
  132. package/lib/server/pageCache.test.ts +76 -77
  133. package/lib/server/pageCache.ts +0 -1
  134. package/lib/server/projectContext.ts +5 -4
  135. package/lib/server/providers/fileSystemCMSProvider.test.ts +142 -99
  136. package/lib/server/providers/fileSystemCMSProvider.ts +62 -38
  137. package/lib/server/routes/api/cms.test.ts +26 -14
  138. package/lib/server/routes/api/cms.ts +9 -14
  139. package/lib/server/routes/api/colors.test.ts +2 -2
  140. package/lib/server/routes/api/components.ts +31 -35
  141. package/lib/server/routes/api/config.ts +3 -4
  142. package/lib/server/routes/api/core-routes.ts +49 -76
  143. package/lib/server/routes/api/enums.test.ts +2 -2
  144. package/lib/server/routes/api/functions.ts +9 -17
  145. package/lib/server/routes/api/index.ts +3 -6
  146. package/lib/server/routes/api/pages.ts +8 -11
  147. package/lib/server/routes/api/shared.test.ts +1 -1
  148. package/lib/server/routes/api/shared.ts +12 -9
  149. package/lib/server/routes/api/variables.test.ts +3 -5
  150. package/lib/server/routes/api/variables.ts +1 -1
  151. package/lib/server/routes/index.ts +25 -28
  152. package/lib/server/routes/pages.ts +35 -31
  153. package/lib/server/routes/static.ts +17 -6
  154. package/lib/server/runtime/bundler.ts +98 -61
  155. package/lib/server/runtime/fs.ts +16 -26
  156. package/lib/server/runtime/httpServer.ts +8 -12
  157. package/lib/server/services/ColorService.test.ts +3 -3
  158. package/lib/server/services/ColorService.ts +37 -29
  159. package/lib/server/services/EnumService.test.ts +4 -8
  160. package/lib/server/services/EnumService.ts +11 -3
  161. package/lib/server/services/VariableService.test.ts +8 -12
  162. package/lib/server/services/VariableService.ts +11 -3
  163. package/lib/server/services/cmsService.test.ts +158 -120
  164. package/lib/server/services/cmsService.ts +36 -146
  165. package/lib/server/services/componentService.test.ts +125 -45
  166. package/lib/server/services/componentService.ts +70 -46
  167. package/lib/server/services/configService.test.ts +22 -45
  168. package/lib/server/services/configService.ts +50 -27
  169. package/lib/server/services/fileWatcherService.ts +42 -8
  170. package/lib/server/services/index.ts +0 -1
  171. package/lib/server/services/pageService.test.ts +8 -10
  172. package/lib/server/services/pageService.ts +32 -18
  173. package/lib/server/ssr/attributeBuilder.ts +18 -8
  174. package/lib/server/ssr/buildErrorOverlay.ts +11 -12
  175. package/lib/server/ssr/clientDataInjector.ts +7 -21
  176. package/lib/server/ssr/cmsSSRProcessor.ts +4 -8
  177. package/lib/server/ssr/cssCollector.ts +1 -1
  178. package/lib/server/ssr/errorOverlay.test.ts +1 -1
  179. package/lib/server/ssr/errorOverlay.ts +3 -9
  180. package/lib/server/ssr/htmlGenerator.nonce.test.ts +9 -14
  181. package/lib/server/ssr/htmlGenerator.test.ts +120 -44
  182. package/lib/server/ssr/htmlGenerator.ts +126 -91
  183. package/lib/server/ssr/imageMetadata.test.ts +3 -1
  184. package/lib/server/ssr/imageMetadata.ts +27 -21
  185. package/lib/server/ssr/jsCollector.test.ts +8 -18
  186. package/lib/server/ssr/jsCollector.ts +3 -8
  187. package/lib/server/ssr/liveReloadIntegration.test.ts +76 -36
  188. package/lib/server/ssr/metaTagGenerator.ts +2 -2
  189. package/lib/server/ssr/ssrRenderer.branches.test.ts +1103 -0
  190. package/lib/server/ssr/ssrRenderer.test.ts +316 -256
  191. package/lib/server/ssr/ssrRenderer.ts +795 -243
  192. package/lib/server/ssrRenderer.test.ts +1048 -954
  193. package/lib/server/utils/jsonLineMapper.test.ts +28 -28
  194. package/lib/server/utils/jsonLineMapper.ts +7 -7
  195. package/lib/server/validateStyleCoverage.ts +18 -21
  196. package/lib/server/websocketManager.ts +28 -19
  197. package/lib/shared/attributeNodeUtils.test.ts +15 -15
  198. package/lib/shared/attributeNodeUtils.ts +5 -12
  199. package/lib/shared/breakpoints.test.ts +5 -5
  200. package/lib/shared/breakpoints.ts +4 -11
  201. package/lib/shared/cmsQuery.test.ts +81 -0
  202. package/lib/shared/cmsQuery.ts +92 -0
  203. package/lib/shared/cmsQueryParser.test.ts +50 -42
  204. package/lib/shared/cmsQueryParser.ts +60 -38
  205. package/lib/shared/colorConversions.ts +9 -9
  206. package/lib/shared/colorVariableUtils.test.ts +27 -5
  207. package/lib/shared/colorVariableUtils.ts +21 -12
  208. package/lib/shared/componentRefs.ts +1 -5
  209. package/lib/shared/constants.test.ts +3 -3
  210. package/lib/shared/constants.ts +8 -8
  211. package/lib/shared/cssGeneration.test.ts +285 -144
  212. package/lib/shared/cssGeneration.ts +217 -531
  213. package/lib/shared/cssNamedColors.ts +152 -30
  214. package/lib/shared/cssProperties.test.ts +69 -70
  215. package/lib/shared/cssProperties.ts +298 -114
  216. package/lib/shared/elementClassName.test.ts +109 -109
  217. package/lib/shared/elementClassName.ts +3 -3
  218. package/lib/shared/elementUtils.ts +12 -16
  219. package/lib/shared/errorLogger.test.ts +12 -12
  220. package/lib/shared/errorLogger.ts +2 -10
  221. package/lib/shared/errors.test.ts +2 -13
  222. package/lib/shared/errors.ts +2 -8
  223. package/lib/shared/expressionEvaluator.test.ts +145 -0
  224. package/lib/shared/expressionEvaluator.ts +52 -24
  225. package/lib/shared/fontLoader.test.ts +32 -18
  226. package/lib/shared/fontLoader.ts +2 -2
  227. package/lib/shared/friendlyError.ts +2 -3
  228. package/lib/shared/gradientUtils.test.ts +3 -7
  229. package/lib/shared/gradientUtils.ts +17 -14
  230. package/lib/shared/hrefRefs.test.ts +2 -2
  231. package/lib/shared/hrefRefs.ts +2 -10
  232. package/lib/shared/i18n.test.ts +4 -4
  233. package/lib/shared/i18n.ts +18 -38
  234. package/lib/shared/index.ts +27 -0
  235. package/lib/shared/inlineSvgStyleRules.ts +14 -13
  236. package/lib/shared/interactiveStyleMappings.test.ts +32 -54
  237. package/lib/shared/interactiveStyleMappings.ts +11 -24
  238. package/lib/shared/interactiveStyles.test.ts +165 -188
  239. package/lib/shared/interfaces/contentProvider.ts +1 -1
  240. package/lib/shared/itemTemplateUtils.test.ts +11 -17
  241. package/lib/shared/itemTemplateUtils.ts +27 -39
  242. package/lib/shared/jsonRepair.ts +16 -10
  243. package/lib/shared/libraryLoader.test.ts +21 -55
  244. package/lib/shared/libraryLoader.ts +7 -22
  245. package/lib/shared/linkUtils.ts +1 -1
  246. package/lib/shared/logger.test.ts +66 -0
  247. package/lib/shared/logger.ts +94 -0
  248. package/lib/shared/markdown.ts +25 -0
  249. package/lib/shared/netlifyLocale404.test.ts +179 -0
  250. package/lib/shared/netlifyLocale404.ts +110 -0
  251. package/lib/shared/nodeUtils.test.ts +28 -16
  252. package/lib/shared/nodeUtils.ts +76 -23
  253. package/lib/shared/pathArrayUtils.test.ts +1 -2
  254. package/lib/shared/pathArrayUtils.ts +1 -1
  255. package/lib/shared/pathSecurity.ts +2 -2
  256. package/lib/shared/pathUtils.test.ts +4 -6
  257. package/lib/shared/pathUtils.ts +42 -49
  258. package/lib/shared/paths/Path.test.ts +2 -2
  259. package/lib/shared/paths/Path.ts +0 -1
  260. package/lib/shared/paths/PathConverter.test.ts +1 -1
  261. package/lib/shared/paths/PathConverter.ts +17 -20
  262. package/lib/shared/paths/PathUtils.ts +13 -13
  263. package/lib/shared/paths/PathValidator.test.ts +2 -15
  264. package/lib/shared/paths/PathValidator.ts +12 -10
  265. package/lib/shared/paths/index.ts +1 -2
  266. package/lib/shared/permissions.test.ts +168 -0
  267. package/lib/shared/permissions.ts +162 -0
  268. package/lib/shared/propResolver.test.ts +240 -244
  269. package/lib/shared/propResolver.ts +15 -26
  270. package/lib/shared/pxToRem.test.ts +7 -6
  271. package/lib/shared/pxToRem.ts +2 -5
  272. package/lib/shared/registry/BaseNodeTypeRegistry.test.ts +12 -6
  273. package/lib/shared/registry/ClientRegistry.ts +0 -2
  274. package/lib/shared/registry/ComponentRegistry.test.ts +46 -32
  275. package/lib/shared/registry/ComponentRegistry.ts +12 -9
  276. package/lib/shared/registry/NodeTypeDefinition.ts +16 -9
  277. package/lib/shared/registry/RegistryManager.ts +1 -2
  278. package/lib/shared/registry/SSRRegistry.ts +0 -2
  279. package/lib/shared/registry/createNodeType.ts +7 -9
  280. package/lib/shared/registry/defineNodeType.ts +2 -6
  281. package/lib/shared/registry/fieldPresets.ts +3 -1
  282. package/lib/shared/registry/index.ts +0 -1
  283. package/lib/shared/registry/nodeTypes/ComponentInstanceNodeType.ts +14 -15
  284. package/lib/shared/registry/nodeTypes/CustomNodeType.ts +103 -0
  285. package/lib/shared/registry/nodeTypes/EmbedNodeType.ts +18 -11
  286. package/lib/shared/registry/nodeTypes/HtmlNodeType.ts +48 -19
  287. package/lib/shared/registry/nodeTypes/IslandNodeType.ts +129 -0
  288. package/lib/shared/registry/nodeTypes/LinkNodeType.ts +21 -19
  289. package/lib/shared/registry/nodeTypes/ListNodeType.ts +117 -77
  290. package/lib/shared/registry/nodeTypes/LocaleListNodeType.ts +27 -21
  291. package/lib/shared/registry/nodeTypes/MarkdownNodeType.ts +78 -0
  292. package/lib/shared/registry/nodeTypes/SlotMarkerType.ts +12 -8
  293. package/lib/shared/registry/nodeTypes/index.ts +26 -3
  294. package/lib/shared/responsiveScaling.test.ts +16 -34
  295. package/lib/shared/responsiveScaling.ts +61 -42
  296. package/lib/shared/responsiveStyleUtils.test.ts +0 -1
  297. package/lib/shared/responsiveStyleUtils.ts +11 -13
  298. package/lib/shared/richtext/htmlToTiptap.test.ts +139 -130
  299. package/lib/shared/richtext/htmlToTiptap.ts +2 -4
  300. package/lib/shared/richtext/tiptapToHtml.test.ts +5 -6
  301. package/lib/shared/richtext/types.ts +1 -8
  302. package/lib/shared/slugTranslator.test.ts +13 -13
  303. package/lib/shared/slugTranslator.ts +12 -16
  304. package/lib/shared/slugify.ts +9 -15
  305. package/lib/shared/styleNodeUtils.test.ts +8 -8
  306. package/lib/shared/styleNodeUtils.ts +18 -20
  307. package/lib/shared/styleUtils.test.ts +87 -61
  308. package/lib/shared/styleUtils.ts +5 -6
  309. package/lib/shared/themeDefaults.test.ts +11 -14
  310. package/lib/shared/themeDefaults.ts +3 -4
  311. package/lib/shared/tree/PathBuilder.test.ts +63 -145
  312. package/lib/shared/tree/PathBuilder.ts +59 -47
  313. package/lib/shared/treePathUtils.test.ts +51 -12
  314. package/lib/shared/treePathUtils.ts +91 -60
  315. package/lib/shared/types/api.ts +105 -8
  316. package/lib/shared/types/cms.test.ts +34 -0
  317. package/lib/shared/types/cms.ts +90 -34
  318. package/lib/shared/types/comment.ts +49 -16
  319. package/lib/shared/types/components.ts +51 -25
  320. package/lib/shared/types/errors.test.ts +1 -6
  321. package/lib/shared/types/errors.ts +3 -7
  322. package/lib/shared/types/experiments.ts +28 -28
  323. package/lib/shared/types/index.ts +25 -2
  324. package/lib/shared/types/permissions.ts +139 -0
  325. package/lib/shared/types/styles.ts +0 -1
  326. package/lib/shared/types/variables.test.ts +4 -13
  327. package/lib/shared/types/variables.ts +51 -30
  328. package/lib/shared/types.ts +1 -2
  329. package/lib/shared/utilityClassConfig.ts +751 -321
  330. package/lib/shared/utilityClassMapper.durability.test.ts +117 -0
  331. package/lib/shared/utilityClassMapper.test.ts +433 -95
  332. package/lib/shared/utilityClassMapper.ts +322 -249
  333. package/lib/shared/utilityClassNames.test.ts +38 -0
  334. package/lib/shared/utilityClassNames.ts +458 -0
  335. package/lib/shared/utils.test.ts +2 -10
  336. package/lib/shared/utils.ts +19 -10
  337. package/lib/shared/validation/cmsValidators.ts +2 -1
  338. package/lib/shared/validation/commentValidators.test.ts +53 -0
  339. package/lib/shared/validation/commentValidators.ts +12 -1
  340. package/lib/shared/validation/index.ts +1 -0
  341. package/lib/shared/validation/permissionsValidators.test.ts +49 -0
  342. package/lib/shared/validation/permissionsValidators.ts +49 -0
  343. package/lib/shared/validation/propValidator.test.ts +19 -21
  344. package/lib/shared/validation/propValidator.ts +13 -18
  345. package/lib/shared/validation/schemas.test.ts +64 -32
  346. package/lib/shared/validation/schemas.ts +616 -345
  347. package/lib/shared/validation/validators.test.ts +3 -8
  348. package/lib/shared/validation/validators.ts +89 -68
  349. package/lib/shared/viewportUnits.integration.test.ts +14 -10
  350. package/lib/shared/viewportUnits.test.ts +24 -23
  351. package/lib/shared/viewportUnits.ts +12 -5
  352. package/lib/test-utils/dom-setup.ts +1 -1
  353. package/lib/test-utils/factories/ConsoleMockFactory.ts +10 -14
  354. package/lib/test-utils/factories/DomMockFactory.ts +17 -23
  355. package/lib/test-utils/factories/EventMockFactory.ts +7 -13
  356. package/lib/test-utils/factories/FetchMockFactory.ts +39 -57
  357. package/lib/test-utils/factories/ServerMockFactory.ts +6 -10
  358. package/lib/test-utils/factories/StoreMockFactory.ts +18 -29
  359. package/lib/test-utils/fixtures.ts +45 -45
  360. package/lib/test-utils/helpers/asyncHelpers.test.ts +15 -18
  361. package/lib/test-utils/helpers/asyncHelpers.ts +11 -20
  362. package/lib/test-utils/helpers.ts +1 -5
  363. package/lib/test-utils/index.ts +0 -4
  364. package/lib/test-utils/mockFactories.ts +13 -19
  365. package/lib/test-utils/mocks.ts +6 -4
  366. package/package.json +3 -5
  367. package/scripts/build-for-publish.mjs +2 -4
  368. package/scripts/build-meno-filter.ts +4 -7
  369. package/tsconfig.json +1 -0
  370. package/vite.config.ts +4 -4
  371. package/build-next.ts +0 -1361
  372. package/build-static.test.ts +0 -424
  373. package/build-static.ts +0 -1074
  374. package/dist/build-static.js +0 -36
  375. package/dist/chunks/chunk-2MHDV5BF.js +0 -251
  376. package/dist/chunks/chunk-2MHDV5BF.js.map +0 -7
  377. package/dist/chunks/chunk-AZQYF6KE.js +0 -559
  378. package/dist/chunks/chunk-AZQYF6KE.js.map +0 -7
  379. package/dist/chunks/chunk-GZHGVVW3.js +0 -322
  380. package/dist/chunks/chunk-GZHGVVW3.js.map +0 -7
  381. package/dist/chunks/chunk-H3GJ4H2U.js.map +0 -7
  382. package/dist/chunks/chunk-I7YIGZXT.js +0 -467
  383. package/dist/chunks/chunk-I7YIGZXT.js.map +0 -7
  384. package/dist/chunks/chunk-IGYR22T6.js +0 -6192
  385. package/dist/chunks/chunk-IGYR22T6.js.map +0 -7
  386. package/dist/chunks/chunk-JGP5A3Y5.js +0 -1136
  387. package/dist/chunks/chunk-JGP5A3Y5.js.map +0 -7
  388. package/dist/chunks/chunk-JGWFTO6P.js.map +0 -7
  389. package/dist/chunks/chunk-O3NAGJP4.js.map +0 -7
  390. package/dist/chunks/chunk-QB2LNO4W.js +0 -77
  391. package/dist/chunks/chunk-QB2LNO4W.js.map +0 -7
  392. package/dist/chunks/chunk-R6XHAFBF.js +0 -3821
  393. package/dist/chunks/chunk-R6XHAFBF.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/chunk-X754AHS5.js.map +0 -7
  397. package/dist/chunks/chunk-YBLHKYFF.js.map +0 -7
  398. package/dist/chunks/configService-R3OGU2UD.js +0 -13
  399. package/dist/chunks/configService-R3OGU2UD.js.map +0 -7
  400. package/dist/chunks/constants-STK2YBIW.js +0 -46
  401. package/dist/chunks/constants-STK2YBIW.js.map +0 -7
  402. package/dist/chunks/fs-JGINUXGL.js.map +0 -7
  403. package/dist/entries/server-router.js +0 -67
  404. package/dist/entries/server-router.js.map +0 -7
  405. package/entries/server-router.tsx +0 -81
  406. package/lib/server/providers/fileSystemPageProvider.ts +0 -160
  407. package/lib/server/webflow/buildWebflow.ts +0 -635
  408. package/lib/server/webflow/index.ts +0 -23
  409. package/lib/server/webflow/nodeToWebflow.test.ts +0 -3170
  410. package/lib/server/webflow/nodeToWebflow.ts +0 -2435
  411. package/lib/server/webflow/styleMapper.test.ts +0 -389
  412. package/lib/server/webflow/styleMapper.ts +0 -695
  413. package/lib/server/webflow/templateWrapper.ts +0 -49
  414. package/lib/server/webflow/types.ts +0 -396
  415. /package/dist/{build-static.js.map → chunks/fs-G3ANWEFP.js.map} +0 -0
package/build-astro.ts CHANGED
@@ -4,49 +4,50 @@
4
4
  * with a shared layout, global CSS, and optional CMS content collections.
5
5
  */
6
6
 
7
- import { existsSync, readdirSync, mkdirSync, rmSync, statSync, copyFileSync, writeFileSync } from "fs";
8
- import { writeFile, readFile } from "fs/promises";
9
- import { join } from "path";
10
- import { createHash } from "crypto";
11
- import { inspect, minifyJS as runtimeMinifyJS } from './lib/server/runtime';
7
+ import { existsSync, readdirSync, mkdirSync, rmSync, statSync, copyFileSync, writeFileSync } from 'node:fs';
8
+ import { writeFile, readFile } from 'node:fs/promises';
9
+ import { join } from 'node:path';
10
+ import { createHash } from 'node:crypto';
12
11
  import {
13
12
  loadJSONFile,
14
13
  loadComponentDirectory,
15
14
  mapPageNameToPath,
16
15
  parseJSON,
17
- loadI18nConfig
18
- } from "./lib/server/jsonLoader";
19
- import { generateSSRHTML } from "./lib/server/ssrRenderer";
20
- import type { SSRHTMLResult } from "./lib/server/ssr/htmlGenerator";
21
- import { projectPaths } from "./lib/server/projectContext";
22
- import { loadProjectConfig, generateFontCSS, generateFontPreloadTags } from "./lib/shared/fontLoader";
23
- import { FileSystemCMSProvider } from "./lib/server/providers/fileSystemCMSProvider";
24
- import { CMSService } from "./lib/server/services/cmsService";
25
- import { isI18nValue, resolveI18nValue } from "./lib/shared/i18n";
26
- import { tiptapToHtml } from "./lib/shared/richtext/tiptapToHtml";
27
- import { isTiptapDocument } from "./lib/shared/richtext/types";
28
- import type { ComponentDefinition, JSONPage, CMSSchema, CMSItem, I18nConfig } from "./lib/shared/types";
29
- import type { CMSFieldDefinition } from "./lib/shared/types/cms";
30
- import { isItemDraftForLocale } from "./lib/shared/types";
31
- import { CMS_DRAFT_SUFFIX } from "./lib/shared/pathSecurity";
32
- import type { SlugMap } from "./lib/shared/slugTranslator";
33
- import { renderPageSSR } from "./lib/server/ssr/ssrRenderer";
34
- import { generateThemeColorVariablesCSS, generateVariablesCSS } from "./lib/server/cssGenerator";
35
- import { colorService } from "./lib/server/services/ColorService";
36
- import { variableService } from "./lib/server/services/VariableService";
37
- import { configService } from "./lib/server/services/configService";
38
- import { loadBreakpointConfig, loadIconsConfig } from "./lib/server/jsonLoader";
39
- import type { InteractiveStyles } from "./lib/shared/types/styles";
40
- import { collectComponentLibraries, filterLibrariesByContext, mergeLibraries, generateLibraryTags } from "./lib/shared/libraryLoader";
41
- import { migrateTemplatesDirectory } from "./lib/server/migrateTemplates";
42
- import { emitAstroComponent } from "./lib/server/astro/componentEmitter";
43
- import { emitAstroPage } from "./lib/server/astro/pageEmitter";
44
- import { normalizeOrphanTemplateProps } from "./lib/server/astro/normalizeOrphanTemplateProps";
16
+ loadI18nConfig,
17
+ } from './lib/server/jsonLoader';
18
+ import { projectPaths } from './lib/server/projectContext';
19
+ import { loadProjectConfig, generateFontCSS, generateFontPreloadTags } from './lib/shared/fontLoader';
20
+ import { FileSystemCMSProvider } from './lib/server/providers/fileSystemCMSProvider';
21
+ import { CMSService } from './lib/server/services/cmsService';
22
+ import { isI18nValue, resolveI18nValue } from './lib/shared/i18n';
23
+ import { syncNetlifyLocale404Block } from './lib/shared/netlifyLocale404';
24
+ import { tiptapToHtml } from './lib/shared/richtext/tiptapToHtml';
25
+ import { isTiptapDocument } from './lib/shared/richtext/types';
26
+ import type { ComponentDefinition, JSONPage, CMSSchema, CMSItem, I18nConfig } from './lib/shared/types';
27
+ import type { CMSFieldDefinition } from './lib/shared/types/cms';
28
+ import { CMS_DRAFT_SUFFIX } from './lib/shared/pathSecurity';
29
+ import type { SlugMap } from './lib/shared/slugTranslator';
30
+ import { type PreloadImage, renderPageSSR } from './lib/server/ssr/ssrRenderer';
31
+ import { generateThemeColorVariablesCSS, generateVariablesCSS } from './lib/server/cssGenerator';
32
+ import { colorService } from './lib/server/services/ColorService';
33
+ import { variableService } from './lib/server/services/VariableService';
34
+ import { configService } from './lib/server/services/configService';
35
+ import { loadBreakpointConfig, loadIconsConfig } from './lib/server/jsonLoader';
36
+ import type { InteractiveStyles } from './lib/shared/types/styles';
37
+ import {
38
+ collectComponentLibraries,
39
+ filterLibrariesByContext,
40
+ mergeLibraries,
41
+ generateLibraryTags,
42
+ } from './lib/shared/libraryLoader';
43
+ import { migrateTemplatesDirectory } from './lib/server/migrateTemplates';
44
+ import { emitAstroComponent } from './lib/server/astro/componentEmitter';
45
+ import { emitAstroPage } from './lib/server/astro/pageEmitter';
46
+ import { normalizeOrphanTemplateProps } from './lib/server/astro/normalizeOrphanTemplateProps';
45
47
  import { emitCMSPage, CMS_SLUG_PLACEHOLDER } from './lib/server/astro/cmsPageEmitter';
46
- import { collectAllMappingClasses } from "./lib/server/astro/cssCollector";
47
- import { buildImageMetadataMap, RESPONSIVE_WIDTHS } from "./lib/server/ssr/imageMetadata";
48
- import { needsFormHandler, formHandlerScript } from "./lib/client/scripts/formHandler";
49
-
48
+ import { collectAllMappingClasses } from './lib/server/astro/cssCollector';
49
+ import { buildImageMetadataMap, RESPONSIVE_WIDTHS } from './lib/server/ssr/imageMetadata';
50
+ import { needsFormHandler, formHandlerScript } from './lib/client/scripts/formHandler';
50
51
 
51
52
  // ---------------------------------------------------------------------------
52
53
  // Helpers
@@ -70,11 +71,7 @@ function writePageScript(javascript: string | undefined, scriptsDir: string): st
70
71
  return [`/_scripts/${scriptFile}`];
71
72
  }
72
73
 
73
- function copyDirectory(
74
- src: string,
75
- dest: string,
76
- filter?: (filename: string) => boolean,
77
- ): void {
74
+ function copyDirectory(src: string, dest: string, filter?: (filename: string) => boolean): void {
78
75
  if (!existsSync(src)) return;
79
76
  if (!existsSync(dest)) mkdirSync(dest, { recursive: true });
80
77
  const files = readdirSync(src);
@@ -91,9 +88,7 @@ function copyDirectory(
91
88
  // Astro's <Picture> re-derives responsive variants from originals at build
92
89
  // time, so the pre-baked -{width}.webp/.avif files and the SSR-only
93
90
  // manifest.json are dead weight in the exported project.
94
- const imageVariantSuffixRe = new RegExp(
95
- `-(${RESPONSIVE_WIDTHS.join('|')})\\.(webp|avif)$`,
96
- );
91
+ const imageVariantSuffixRe = new RegExp(`-(${RESPONSIVE_WIDTHS.join('|')})\\.(webp|avif)$`);
97
92
  function shouldCopyImageForAstro(filename: string): boolean {
98
93
  if (filename === 'manifest.json') return false;
99
94
  if (imageVariantSuffixRe.test(filename)) return false;
@@ -107,12 +102,12 @@ function isCMSPage(pageData: JSONPage): boolean {
107
102
  /**
108
103
  * Build URL path for a CMS item based on the URL pattern
109
104
  */
110
- function buildCMSItemPath(
105
+ function _buildCMSItemPath(
111
106
  urlPattern: string,
112
107
  item: CMSItem,
113
108
  slugField: string,
114
109
  locale: string,
115
- i18nConfig: I18nConfig
110
+ i18nConfig: I18nConfig,
116
111
  ): string {
117
112
  let slug = item[slugField] ?? item._slug ?? item._id;
118
113
  if (isI18nValue(slug)) {
@@ -160,10 +155,7 @@ function escapeTemplateLiteral(s: string): string {
160
155
  * Compute locale → URL path map for a page's slug translations.
161
156
  * Used by locale list rendering to generate correct links.
162
157
  */
163
- function computePageSlugMap(
164
- slugs: Record<string, string>,
165
- i18nConfig: I18nConfig
166
- ): Record<string, string> {
158
+ function computePageSlugMap(slugs: Record<string, string>, i18nConfig: I18nConfig): Record<string, string> {
167
159
  const map: Record<string, string> = {};
168
160
  for (const localeConfig of i18nConfig.locales) {
169
161
  const code = localeConfig.code;
@@ -198,7 +190,7 @@ function cmsFieldToZod(field: CMSFieldDefinition): string {
198
190
  return 'z.coerce.date()';
199
191
  case 'select':
200
192
  if (field.options && field.options.length > 0) {
201
- const opts = field.options.map(o => `'${o.replace(/'/g, "\\'")}'`).join(', ');
193
+ const opts = field.options.map((o) => `'${o.replace(/'/g, "\\'")}'`).join(', ');
202
194
  return `z.enum([${opts}])`;
203
195
  }
204
196
  return 'z.string()';
@@ -263,9 +255,7 @@ function collectComponentRefs(node: unknown, acc: Set<string>): void {
263
255
  * structure (it must forward the `cms` prop down). Astro components have
264
256
  * isolated scopes, so each consumer needs the entry threaded in explicitly.
265
257
  */
266
- function computeCmsConsumerComponents(
267
- components: Record<string, ComponentDefinition>
268
- ): Set<string> {
258
+ function computeCmsConsumerComponents(components: Record<string, ComponentDefinition>): Set<string> {
269
259
  const consumers = new Set<string>();
270
260
  const refsByComponent = new Map<string, Set<string>>();
271
261
 
@@ -286,7 +276,11 @@ function computeCmsConsumerComponents(
286
276
  for (const [name, refs] of refsByComponent) {
287
277
  if (consumers.has(name)) continue;
288
278
  for (const ref of refs) {
289
- if (consumers.has(ref)) { consumers.add(name); changed = true; break; }
279
+ if (consumers.has(ref)) {
280
+ consumers.add(name);
281
+ changed = true;
282
+ break;
283
+ }
290
284
  }
291
285
  }
292
286
  }
@@ -301,8 +295,8 @@ function computeCmsConsumerComponents(
301
295
  function buildCollectionUrlExpr(schema: CMSSchema): string {
302
296
  const slugField = schema.slugField || 'slug';
303
297
  const pattern = schema.urlPattern || `/${schema.id}/{{slug}}`;
304
- const body = pattern.replace(/\{\{[^}]+\}\}/, '${e.data.' + slugField + ' ?? e.id}');
305
- return '`' + body + '`';
298
+ const body = pattern.replace(/\{\{[^}]+\}\}/, `\${e.data.${slugField} ?? e.id}`);
299
+ return `\`${body}\``;
306
300
  }
307
301
 
308
302
  // ---------------------------------------------------------------------------
@@ -359,15 +353,13 @@ function buildSSRFallbackPage(
359
353
  fontPreloads: string,
360
354
  libraryTags: { headCSS?: string; headJS?: string; bodyEndJS?: string },
361
355
  defaultTheme: string,
362
- scriptPaths: string[]
356
+ scriptPaths: string[],
363
357
  ): string {
364
358
  const escapedMeta = escapeTemplateLiteral(result.meta);
365
359
  const escapedHTML = escapeTemplateLiteral(result.html);
366
360
  const escapedFontPreloads = escapeTemplateLiteral(fontPreloads);
367
361
 
368
- const scriptsArrayLiteral = scriptPaths.length > 0
369
- ? `[${scriptPaths.map(s => `"${s}"`).join(', ')}]`
370
- : '[]';
362
+ const scriptsArrayLiteral = scriptPaths.length > 0 ? `[${scriptPaths.map((s) => `"${s}"`).join(', ')}]` : '[]';
371
363
 
372
364
  const libraryTagsLiteral = `{ headCSS: \`${escapeTemplateLiteral(libraryTags.headCSS || '')}\`, headJS: \`${escapeTemplateLiteral(libraryTags.headJS || '')}\`, bodyEndJS: \`${escapeTemplateLiteral(libraryTags.bodyEndJS || '')}\` }`;
373
365
 
@@ -392,10 +384,7 @@ import BaseLayout from '${importPath}';
392
384
  // Main export
393
385
  // ---------------------------------------------------------------------------
394
386
 
395
- export async function buildAstroProject(
396
- projectRoot?: string,
397
- outputDir?: string
398
- ): Promise<AstroBuildStats> {
387
+ export async function buildAstroProject(_projectRoot?: string, outputDir?: string): Promise<AstroBuildStats> {
399
388
  // ----------------------------------------------------------
400
389
  // 1. Setup: load project configuration
401
390
  // ----------------------------------------------------------
@@ -410,7 +399,9 @@ export async function buildAstroProject(
410
399
 
411
400
  const { components, warnings, errors: compErrors } = await loadComponentDirectory(projectPaths.components());
412
401
  const globalComponents: Record<string, ComponentDefinition> = {};
413
- components.forEach((value, key) => { globalComponents[key] = value; });
402
+ components.forEach((value, key) => {
403
+ globalComponents[key] = value;
404
+ });
414
405
  for (const w of warnings) console.warn(` Warning: ${w}`);
415
406
  for (const e of compErrors) console.error(` Error: ${e}`);
416
407
 
@@ -481,7 +472,9 @@ export async function buildAstroProject(
481
472
  const pageId = basePath === '/' ? 'index' : basePath.substring(1);
482
473
  slugMappings.push({ pageId, slugs: pageData.meta.slugs });
483
474
  }
484
- } catch { /* ignore parse errors in first pass */ }
475
+ } catch {
476
+ /* ignore parse errors in first pass */
477
+ }
485
478
  }
486
479
 
487
480
  // ----------------------------------------------------------
@@ -505,13 +498,25 @@ export async function buildAstroProject(
505
498
 
506
499
  // Helper to process a render result
507
500
  function processRenderResult(
508
- result: { html: string; meta: string; title: string; javascript: string; componentCSS?: string; locale: string; interactiveStylesMap: Map<string, InteractiveStyles>; preloadImages: any[]; neededCollections: Set<string>; ssrFallbackCollector?: Map<string, string>; processedRawHtmlCollector?: Map<string, string> },
501
+ result: {
502
+ html: string;
503
+ meta: string;
504
+ title: string;
505
+ javascript: string;
506
+ componentCSS?: string;
507
+ locale: string;
508
+ interactiveStylesMap: Map<string, InteractiveStyles>;
509
+ preloadImages: PreloadImage[];
510
+ neededCollections: Set<string>;
511
+ ssrFallbackCollector?: Map<string, string>;
512
+ processedRawHtmlCollector?: Map<string, string>;
513
+ },
509
514
  urlPath: string,
510
515
  astroFilePath: string,
511
516
  fileDepth: number,
512
517
  pageData?: JSONPage,
513
518
  pageName?: string,
514
- isCMSPage?: boolean
519
+ isCMSPage?: boolean,
515
520
  ): void {
516
521
  // Collect interactive styles
517
522
  mergeInteractiveStyles(result.interactiveStylesMap);
@@ -582,7 +587,7 @@ export async function buildAstroProject(
582
587
 
583
588
  // Compute URL path
584
589
  let slug: string;
585
- if (slugs && slugs[locale]) {
590
+ if (slugs?.[locale]) {
586
591
  // Slugs may be authored with a leading slash (e.g. "/blog" from the
587
592
  // page-rename flow). Normalize to the bare form the rest of the
588
593
  // pipeline expects — matches buildPageUrlForLocale(). A leading slash
@@ -596,8 +601,12 @@ export async function buildAstroProject(
596
601
  }
597
602
 
598
603
  const urlPath = isDefault
599
- ? (slug === '' ? '/' : `/${slug}`)
600
- : (slug === '' ? `/${locale}` : `/${locale}/${slug}`);
604
+ ? slug === ''
605
+ ? '/'
606
+ : `/${slug}`
607
+ : slug === ''
608
+ ? `/${locale}`
609
+ : `/${locale}/${slug}`;
601
610
 
602
611
  // Determine .astro file path relative to src/pages/
603
612
  const astroFileName = slug === '' ? 'index.astro' : `${slug}.astro`;
@@ -614,13 +623,13 @@ export async function buildAstroProject(
614
623
  slugMappings,
615
624
  undefined, // cmsContext
616
625
  cmsService,
617
- true // isProductionBuild
626
+ true, // isProductionBuild
618
627
  );
619
628
 
620
629
  processRenderResult(result, urlPath, astroFilePath, fileDepth, pageData, pageName, false);
621
630
  }
622
- } catch (error: any) {
623
- console.error(` Error rendering ${basePath}:`, error?.message || error);
631
+ } catch (error) {
632
+ console.error(` Error rendering ${basePath}:`, error instanceof Error ? error.message : error);
624
633
  errorCount++;
625
634
  }
626
635
  }
@@ -708,12 +717,14 @@ export async function buildAstroProject(
708
717
  for (const [fn, fd] of Object.entries(schema.fields || {})) {
709
718
  if (fd.type === 'rich-text') mergedRichTextFields.add(fn);
710
719
  }
711
- } catch { /* ignore parse errors; handled in main loop */ }
720
+ } catch {
721
+ /* ignore parse errors; handled in main loop */
722
+ }
712
723
  }
713
724
  }
714
725
 
715
726
  if (existsSync(templatesDir)) {
716
- const templateFiles = readdirSync(templatesDir).filter(f => f.endsWith('.json'));
727
+ const templateFiles = readdirSync(templatesDir).filter((f) => f.endsWith('.json'));
717
728
 
718
729
  for (const file of templateFiles) {
719
730
  const templateContent = await loadJSONFile(join(templatesDir, file));
@@ -735,6 +746,10 @@ export async function buildAstroProject(
735
746
  const cmsSchema = pageData.meta!.cms as CMSSchema;
736
747
  templateSchemas.push(cmsSchema);
737
748
 
749
+ // A data-only collection (no urlPattern) has no per-item route — skip page/route
750
+ // generation. It is still a content collection usable in list bindings.
751
+ if (!cmsSchema.urlPattern) continue;
752
+
738
753
  // Count items for stats
739
754
  const items = await cmsService.queryItems({ collection: cmsSchema.id });
740
755
  const itemCount = items.length;
@@ -753,7 +768,7 @@ export async function buildAstroProject(
753
768
  slugMappings,
754
769
  undefined, // no CMS context - just collecting metadata
755
770
  cmsService,
756
- true
771
+ true,
757
772
  );
758
773
 
759
774
  // Collect interactive styles and component CSS
@@ -791,13 +806,9 @@ export async function buildAstroProject(
791
806
  // Route file path: blog/[slug].astro for default, pl/blog/[slug].astro for non-default
792
807
  let astroFilePath: string;
793
808
  if (pathPrefix) {
794
- astroFilePath = isDefault
795
- ? `${pathPrefix}[slug].astro`
796
- : `${localeCode}/${pathPrefix}[slug].astro`;
809
+ astroFilePath = isDefault ? `${pathPrefix}[slug].astro` : `${localeCode}/${pathPrefix}[slug].astro`;
797
810
  } else {
798
- astroFilePath = isDefault
799
- ? '[slug].astro'
800
- : `${localeCode}/[slug].astro`;
811
+ astroFilePath = isDefault ? '[slug].astro' : `${localeCode}/[slug].astro`;
801
812
  }
802
813
 
803
814
  const fileDepth = astroFilePath.split('/').length - 1;
@@ -841,8 +852,8 @@ export async function buildAstroProject(
841
852
  }
842
853
 
843
854
  cmsPageCount += itemCount * i18nConfig.locales.length;
844
- } catch (error: any) {
845
- console.error(` Error processing template ${file}:`, error?.message || error);
855
+ } catch (error) {
856
+ console.error(` Error processing template ${file}:`, error instanceof Error ? error.message : error);
846
857
  errorCount++;
847
858
  }
848
859
  }
@@ -870,9 +881,7 @@ export async function buildAstroProject(
870
881
  }`;
871
882
 
872
883
  const safelistClasses = Array.from(mappingClasses);
873
- const safelistDirectives = safelistClasses
874
- .map(c => `@source inline("${c}");`)
875
- .join('\n');
884
+ const safelistDirectives = safelistClasses.map((c) => `@source inline("${c}");`).join('\n');
876
885
  const tailwindDirectives = safelistDirectives
877
886
  ? `@import "tailwindcss";\n\n${safelistDirectives}`
878
887
  : `@import "tailwindcss";`;
@@ -888,19 +897,14 @@ export async function buildAstroProject(
888
897
  // ----------------------------------------------------------
889
898
  // Escape for embedding inside Astro <Fragment set:html={`...`}> template
890
899
  // literals in the generated BaseLayout file.
891
- const escForTemplateLiteral = (s: string) => s
892
- .replace(/\\/g, '\\\\')
893
- .replace(/`/g, '\\`')
894
- .replace(/\$\{/g, '\\${');
900
+ const escForTemplateLiteral = (s: string) => s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
895
901
 
896
902
  const customHeadLiteral = escForTemplateLiteral(customCode.head || '');
897
903
  const customBodyStartLiteral = escForTemplateLiteral(customCode.bodyStart || '');
898
904
  const customBodyEndLiteral = escForTemplateLiteral(customCode.bodyEnd || '');
899
905
  const iconTagsLiteral = escForTemplateLiteral(iconTagsHtml);
900
906
 
901
- const formHandlerBlock = projectNeedsFormHandler
902
- ? `\n <script is:inline>\n${formHandlerScript}\n </script>`
903
- : '';
907
+ const formHandlerBlock = projectNeedsFormHandler ? `\n <script is:inline>\n${formHandlerScript}\n </script>` : '';
904
908
 
905
909
  const baseLayoutContent = `---
906
910
  import '../styles/global.css';
@@ -951,18 +955,29 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
951
955
  // onto each component's interface and forward them from hosts that
952
956
  // declare the same prop. See `normalizeOrphanTemplateProps` for details.
953
957
  const emittableComponents = normalizeOrphanTemplateProps(globalComponents);
954
- let componentFileCount = 0;
958
+ let _componentFileCount = 0;
955
959
  for (const [compName, compDef] of Object.entries(emittableComponents)) {
956
960
  try {
957
- const astroContent = emitAstroComponent(compName, compDef, emittableComponents, breakpoints, i18nConfig.defaultLocale, responsiveScales, remConversionConfig, {
958
- cmsConsumers: cmsConsumerComponents,
959
- cmsRichTextFields: mergedRichTextFields,
960
- collectionUrlExpr,
961
- });
961
+ const astroContent = emitAstroComponent(
962
+ compName,
963
+ compDef,
964
+ emittableComponents,
965
+ breakpoints,
966
+ i18nConfig.defaultLocale,
967
+ responsiveScales,
968
+ remConversionConfig,
969
+ {
970
+ cmsConsumers: cmsConsumerComponents,
971
+ cmsRichTextFields: mergedRichTextFields,
972
+ collectionUrlExpr,
973
+ },
974
+ );
962
975
  await writeFile(join(componentsOutDir, `${compName}.astro`), astroContent, 'utf-8');
963
- componentFileCount++;
964
- } catch (error: any) {
965
- console.warn(` Warning: could not generate component ${compName}: ${error?.message}`);
976
+ _componentFileCount++;
977
+ } catch (error) {
978
+ console.warn(
979
+ ` Warning: could not generate component ${compName}: ${error instanceof Error ? error.message : String(error)}`,
980
+ );
966
981
  }
967
982
  }
968
983
  // ----------------------------------------------------------
@@ -983,10 +998,9 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
983
998
  const ssrFallbacks = result.ssrFallbackCollector ?? new Map<string, string>();
984
999
 
985
1000
  // Compute slug map for locale list rendering
986
- const pageSlugMap: Record<string, string> | undefined =
987
- result.pageData.meta?.slugs
988
- ? computePageSlugMap(result.pageData.meta.slugs, i18nConfig)
989
- : undefined;
1001
+ const pageSlugMap: Record<string, string> | undefined = result.pageData.meta?.slugs
1002
+ ? computePageSlugMap(result.pageData.meta.slugs, i18nConfig)
1003
+ : undefined;
990
1004
 
991
1005
  // Component-structured pages don't need page-level _scripts/*.js
992
1006
  // because each .astro component already has its own inline <script>
@@ -1014,9 +1028,11 @@ const { title, meta = '', scripts = [], locale = 'en', theme = '${themeConfig.de
1014
1028
  processedRawHtml: result.processedRawHtmlCollector,
1015
1029
  remConfig: remConversionConfig,
1016
1030
  });
1017
- } catch (error: any) {
1031
+ } catch (error) {
1018
1032
  // Fallback to SSR HTML if component emission fails — needs page-level script
1019
- console.warn(` Warning: component emission failed for ${result.urlPath}, using SSR fallback: ${error?.message}`);
1033
+ console.warn(
1034
+ ` Warning: component emission failed for ${result.urlPath}, using SSR fallback: ${error instanceof Error ? error.message : String(error)}`,
1035
+ );
1020
1036
  scriptPaths = writePageScript(result.javascript, scriptsDir);
1021
1037
  astroContent = buildSSRFallbackPage(result, importPath, fontPreloads, libraryTags, defaultTheme, scriptPaths);
1022
1038
  }
@@ -1084,8 +1100,8 @@ export const GET: APIRoute = () => {
1084
1100
  // Skip `*.draft.json` siblings in production builds — they mirror the
1085
1101
  // published item-list filter and may hold partial/invalid WIP data.
1086
1102
  const isDevBuild = process.env.MENO_DEV_BUILD === 'true';
1087
- const itemFiles = readdirSync(cmsItemsDir).filter(f =>
1088
- f.endsWith('.json') && (isDevBuild || !f.endsWith(`${CMS_DRAFT_SUFFIX}.json`))
1103
+ const itemFiles = readdirSync(cmsItemsDir).filter(
1104
+ (f) => f.endsWith('.json') && (isDevBuild || !f.endsWith(`${CMS_DRAFT_SUFFIX}.json`)),
1089
1105
  );
1090
1106
 
1091
1107
  for (const itemFile of itemFiles) {
@@ -1102,13 +1118,11 @@ export const GET: APIRoute = () => {
1102
1118
  resolved[fieldName] = serializeRichTextValue(resolved[fieldName]);
1103
1119
  }
1104
1120
 
1105
- await writeFile(
1106
- join(collectionDir, itemFile),
1107
- JSON.stringify(resolved, null, 2),
1108
- 'utf-8'
1121
+ await writeFile(join(collectionDir, itemFile), JSON.stringify(resolved, null, 2), 'utf-8');
1122
+ } catch (err) {
1123
+ console.warn(
1124
+ ` Warning: could not process CMS item ${itemFile}: ${err instanceof Error ? err.message : String(err)}`,
1109
1125
  );
1110
- } catch (err: any) {
1111
- console.warn(` Warning: could not process CMS item ${itemFile}: ${err?.message}`);
1112
1126
  }
1113
1127
  }
1114
1128
  }
@@ -1173,7 +1187,7 @@ export { collections };
1173
1187
  const srcAssetDir = join(projectPaths.project, dir);
1174
1188
  if (existsSync(srcAssetDir)) {
1175
1189
  copyDirectory(srcAssetDir, join(publicDir, dir));
1176
- }
1190
+ }
1177
1191
  }
1178
1192
 
1179
1193
  // Copy libraries folder if it exists
@@ -1212,20 +1226,21 @@ export { collections };
1212
1226
  dependencies: {
1213
1227
  // Astro 5 (stable Vite), NOT 6 — Astro 6's rolldown-vite breaks
1214
1228
  // @tailwindcss/vite at build time ("Missing field `tsconfigPaths`").
1215
- 'astro': '^5.0.0',
1229
+ astro: '^5.0.0',
1216
1230
  '@astrojs/sitemap': '^3.0.0',
1217
1231
  '@tailwindcss/vite': '^4.0.0',
1218
- 'tailwindcss': '^4.0.0',
1232
+ tailwindcss: '^4.0.0',
1219
1233
  },
1220
1234
  };
1221
1235
 
1222
1236
  await writeFile(join(outDir, 'package.json'), JSON.stringify(packageJson, null, 2), 'utf-8');
1223
1237
 
1224
1238
  // astro.config.mjs
1225
- const localeCodes = i18nConfig.locales.map(l => l.code);
1226
- const i18nBlock = i18nConfig.locales.length > 1
1227
- ? `\n i18n: {\n defaultLocale: '${i18nConfig.defaultLocale}',\n locales: [${localeCodes.map(c => `'${c}'`).join(', ')}],\n routing: { prefixDefaultLocale: false },\n },`
1228
- : '';
1239
+ const localeCodes = i18nConfig.locales.map((l) => l.code);
1240
+ const i18nBlock =
1241
+ i18nConfig.locales.length > 1
1242
+ ? `\n i18n: {\n defaultLocale: '${i18nConfig.defaultLocale}',\n locales: [${localeCodes.map((c) => `'${c}'`).join(', ')}],\n routing: { prefixDefaultLocale: false },\n },`
1243
+ : '';
1229
1244
 
1230
1245
  const astroConfig = `import { defineConfig } from 'astro/config';
1231
1246
  import tailwindcss from '@tailwindcss/vite';
@@ -1252,7 +1267,13 @@ export default defineConfig({${siteUrl ? `\n site: '${siteUrl}',` : ''}${i18nBl
1252
1267
  // box. `astro` is a real dependency here (see package.json above), so once
1253
1268
  // Netlify runs `npm install`, `astro build` is on PATH and writes to dist/.
1254
1269
  // Harmless on other hosts (Cloudflare Pages / Vercel ignore this file).
1255
- const netlifyToml = `# Generated by Meno's Astro build.
1270
+ //
1271
+ // Multi-locale projects WITH a 404 page (pages/404.json) also get the managed
1272
+ // locale-404 redirects block (lib/shared/netlifyLocale404.ts): the regular-pages
1273
+ // loop above emits src/pages/<locale>/404.astro per non-default locale, which
1274
+ // Astro builds to dist/<locale>/404/index.html — exactly the rules' rewrite
1275
+ // target — while the root 404.astro becomes Netlify's default catch-all 404.html.
1276
+ const baseNetlifyToml = `# Generated by Meno's Astro build.
1256
1277
  [build]
1257
1278
  command = "npm run build"
1258
1279
  publish = "dist"
@@ -1260,6 +1281,7 @@ export default defineConfig({${siteUrl ? `\n site: '${siteUrl}',` : ''}${i18nBl
1260
1281
  [build.environment]
1261
1282
  NODE_VERSION = "22"
1262
1283
  `;
1284
+ const netlifyToml = syncNetlifyLocale404Block(baseNetlifyToml, i18nConfig, pageFiles.includes('404.json'));
1263
1285
  await writeFile(join(outDir, 'netlify.toml'), netlifyToml, 'utf-8');
1264
1286
 
1265
1287
  // src/env.d.ts — resolves astro:assets and other virtual module types in IDE