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
@@ -35,7 +35,7 @@ export interface CoreRouteContext {
35
35
  export async function handleCoreApiRoutes(
36
36
  req: Request,
37
37
  url: URL,
38
- context: CoreRouteContext
38
+ context: CoreRouteContext,
39
39
  ): Promise<Response | undefined> {
40
40
  const { pageService, componentService, cmsService } = context;
41
41
 
@@ -55,21 +55,21 @@ export async function handleCoreApiRoutes(
55
55
  if (url.pathname === API_ROUTES.PAGES && req.method === 'GET') {
56
56
  return await handleRouteError(
57
57
  () => Promise.resolve(pagesRoutes.handlePagesRoute(pageService)),
58
- 'Failed to fetch pages list'
58
+ 'Failed to fetch pages list',
59
59
  );
60
60
  }
61
61
 
62
62
  if (url.pathname.startsWith(API_ROUTES.PAGE_DATA) && req.method === 'GET') {
63
63
  return await handleRouteError(
64
64
  () => Promise.resolve(pagesRoutes.handlePageDataRoute(url, pageService)),
65
- 'Failed to fetch page data'
65
+ 'Failed to fetch page data',
66
66
  );
67
67
  }
68
68
 
69
69
  if (url.pathname === API_ROUTES.PAGE_CONTENT && req.method === 'GET') {
70
70
  return await handleRouteError(
71
71
  () => Promise.resolve(pagesRoutes.handlePageContentRoute(req, url, pageService)),
72
- 'Failed to fetch page content'
72
+ 'Failed to fetch page content',
73
73
  );
74
74
  }
75
75
 
@@ -77,135 +77,108 @@ export async function handleCoreApiRoutes(
77
77
  if (url.pathname === API_ROUTES.COMPONENTS && req.method === 'GET') {
78
78
  return await handleRouteError(
79
79
  () => Promise.resolve(componentsRoutes.handleComponentsRoute(req, componentService)),
80
- 'Failed to fetch components list'
80
+ 'Failed to fetch components list',
81
81
  );
82
82
  }
83
83
 
84
84
  if (url.pathname.startsWith('/api/component-data/') && req.method === 'GET') {
85
85
  return await handleRouteError(
86
86
  () => Promise.resolve(componentsRoutes.handleComponentDataRoute(url, componentService)),
87
- 'Failed to fetch component data'
87
+ 'Failed to fetch component data',
88
88
  );
89
89
  }
90
90
 
91
91
  if (url.pathname.startsWith('/api/component-js/') && req.method === 'GET') {
92
92
  return await handleRouteError(
93
93
  () => componentsRoutes.handleComponentJavaScriptRoute(url, componentService),
94
- 'Failed to fetch component JavaScript'
94
+ 'Failed to fetch component JavaScript',
95
95
  );
96
96
  }
97
97
 
98
98
  // Config API routes (read-only)
99
99
  if (url.pathname === '/api/config' && req.method === 'GET') {
100
- return await handleRouteError(
101
- () => configRoutes.handleConfigRoute(),
102
- 'Failed to fetch config'
103
- );
100
+ return await handleRouteError(() => configRoutes.handleConfigRoute(), 'Failed to fetch config');
104
101
  }
105
102
 
106
103
  if (url.pathname === '/api/components-config' && req.method === 'GET') {
107
104
  return await handleRouteError(
108
105
  () => configRoutes.handleComponentsConfigRoute(),
109
- 'Failed to fetch components config'
106
+ 'Failed to fetch components config',
110
107
  );
111
108
  }
112
109
 
113
110
  // Colors API routes (read-only)
114
111
  if (url.pathname === '/api/colors' && req.method === 'GET') {
115
- return await handleRouteError(
116
- () => colorsRoutes.handleColorsRoute(url),
117
- 'Failed to fetch colors'
118
- );
112
+ return await handleRouteError(() => colorsRoutes.handleColorsRoute(url), 'Failed to fetch colors');
119
113
  }
120
114
 
121
115
  if (url.pathname === '/api/themes' && req.method === 'GET') {
122
- return await handleRouteError(
123
- () => colorsRoutes.handleThemesRoute(),
124
- 'Failed to fetch themes'
125
- );
116
+ return await handleRouteError(() => colorsRoutes.handleThemesRoute(), 'Failed to fetch themes');
126
117
  }
127
118
 
128
119
  if (url.pathname === '/api/colors-config' && req.method === 'GET') {
129
- return await handleRouteError(
130
- () => colorsRoutes.handleColorsConfigRoute(),
131
- 'Failed to fetch colors config'
132
- );
120
+ return await handleRouteError(() => colorsRoutes.handleColorsConfigRoute(), 'Failed to fetch colors config');
133
121
  }
134
122
 
135
123
  if (url.pathname === '/api/colors-status' && req.method === 'GET') {
136
- return await handleRouteError(
137
- () => colorsRoutes.handleColorsStatusRoute(),
138
- 'Failed to fetch colors status'
139
- );
124
+ return await handleRouteError(() => colorsRoutes.handleColorsStatusRoute(), 'Failed to fetch colors status');
140
125
  }
141
126
 
142
127
  // Variables API routes (read-only)
143
128
  if (url.pathname === '/api/variables-status' && req.method === 'GET') {
144
129
  return await handleRouteError(
145
130
  () => variablesRoutes.handleVariablesStatusRoute(),
146
- 'Failed to fetch variables status'
131
+ 'Failed to fetch variables status',
147
132
  );
148
133
  }
149
134
 
150
135
  if (url.pathname === '/api/variables-css' && req.method === 'GET') {
151
- return await handleRouteError(
152
- () => variablesRoutes.handleVariablesCSSRoute(),
153
- 'Failed to generate variables CSS'
154
- );
136
+ return await handleRouteError(() => variablesRoutes.handleVariablesCSSRoute(), 'Failed to generate variables CSS');
155
137
  }
156
138
 
157
139
  // Fonts CSS route (read-only)
158
140
  if (url.pathname === '/api/fonts-css' && req.method === 'GET') {
159
- return await handleRouteError(
160
- async () => {
161
- await loadProjectConfig();
162
- const css = generateFontCSS();
163
- return new Response(css, {
164
- headers: { 'Content-Type': 'text/css' },
165
- });
166
- },
167
- 'Failed to generate fonts CSS'
168
- );
141
+ return await handleRouteError(async () => {
142
+ await loadProjectConfig();
143
+ const css = generateFontCSS();
144
+ return new Response(css, {
145
+ headers: { 'Content-Type': 'text/css' },
146
+ });
147
+ }, 'Failed to generate fonts CSS');
169
148
  }
170
149
 
171
150
  // Enums API route (read-only)
172
151
  if (url.pathname === '/api/enums' && req.method === 'GET') {
173
- return await handleRouteError(
174
- () => enumsRoutes.handleEnumsRoute(),
175
- 'Failed to fetch enums'
176
- );
152
+ return await handleRouteError(() => enumsRoutes.handleEnumsRoute(), 'Failed to fetch enums');
177
153
  }
178
154
 
179
155
  // Usage API route (for license limit checks)
180
156
  if (url.pathname === '/api/usage' && req.method === 'GET') {
181
- return await handleRouteError(
182
- () => {
183
- // Count CMS collections
184
- const cmsCollections = cmsService ? cmsService.getAllSchemas().size : 0;
185
-
186
- // Count pages (exclude templates directory)
187
- const allPages = pageService.getAllPagePaths();
188
- const pages = allPages.filter(p => !p.includes('/templates/')).length;
189
-
190
- // Count locales from config
191
- const i18n = configService.getI18n();
192
- const locales = i18n.locales.length;
193
-
194
- return Promise.resolve(
195
- new Response(JSON.stringify({ cmsCollections, pages, locales }), {
196
- headers: { 'Content-Type': 'application/json' }
197
- })
198
- );
199
- },
200
- 'Failed to fetch usage stats'
201
- );
157
+ return await handleRouteError(() => {
158
+ // Count CMS collections
159
+ const cmsCollections = cmsService ? cmsService.getAllSchemas().size : 0;
160
+
161
+ // Count pages (exclude templates directory)
162
+ const allPages = pageService.getAllPagePaths();
163
+ const pages = allPages.filter((p) => !p.includes('/templates/')).length;
164
+
165
+ // Count locales from config
166
+ const i18n = configService.getI18n();
167
+ const locales = i18n.locales.length;
168
+
169
+ return Promise.resolve(
170
+ new Response(JSON.stringify({ cmsCollections, pages, locales }), {
171
+ headers: { 'Content-Type': 'application/json' },
172
+ }),
173
+ );
174
+ }, 'Failed to fetch usage stats');
202
175
  }
203
176
 
204
177
  // Component usage API route (read-only)
205
178
  if (url.pathname === API_ROUTES.COMPONENT_USAGE && req.method === 'GET') {
206
179
  return await handleRouteError(
207
180
  () => Promise.resolve(componentsRoutes.handleComponentUsageRoute(pageService, componentService)),
208
- 'Failed to fetch component usage'
181
+ 'Failed to fetch component usage',
209
182
  );
210
183
  }
211
184
 
@@ -213,7 +186,7 @@ export async function handleCoreApiRoutes(
213
186
  if (url.pathname === '/api/slug-mappings' && req.method === 'GET') {
214
187
  return await handleRouteError(
215
188
  () => Promise.resolve(pagesRoutes.handleSlugMappingsRoute(pageService)),
216
- 'Failed to fetch slug mappings'
189
+ 'Failed to fetch slug mappings',
217
190
  );
218
191
  }
219
192
 
@@ -223,23 +196,23 @@ export async function handleCoreApiRoutes(
223
196
  if (url.pathname === '/api/cms/collections' && req.method === 'GET') {
224
197
  return await handleRouteError(
225
198
  () => Promise.resolve(cmsRoutes.handleCollectionsRoute(cmsService)),
226
- 'Failed to fetch CMS collections'
199
+ 'Failed to fetch CMS collections',
227
200
  );
228
201
  }
229
202
 
230
203
  // GET /api/cms/collections/:collection - Get collection schema
231
204
  const collectionSchemaMatch = url.pathname.match(/^\/api\/cms\/collections\/([^/]+)$/);
232
- if (collectionSchemaMatch && req.method === 'GET') {
205
+ if (collectionSchemaMatch && collectionSchemaMatch[1] !== undefined && req.method === 'GET') {
233
206
  const collection = collectionSchemaMatch[1];
234
207
  return await handleRouteError(
235
208
  () => Promise.resolve(cmsRoutes.handleCollectionSchemaRoute(collection, cmsService)),
236
- 'Failed to fetch collection schema'
209
+ 'Failed to fetch collection schema',
237
210
  );
238
211
  }
239
212
 
240
213
  // Parse collection and slug from path: /api/cms/:collection/:slug?
241
214
  const cmsPathMatch = url.pathname.match(/^\/api\/cms\/([^/]+)(?:\/([^/]+))?$/);
242
- if (cmsPathMatch) {
215
+ if (cmsPathMatch && cmsPathMatch[1] !== undefined) {
243
216
  const collection = cmsPathMatch[1];
244
217
  const slug = cmsPathMatch[2];
245
218
 
@@ -252,7 +225,7 @@ export async function handleCoreApiRoutes(
252
225
  if (!slug && req.method === 'GET') {
253
226
  return await handleRouteError(
254
227
  () => cmsRoutes.handleItemsRoute(collection, cmsService, url.searchParams),
255
- 'Failed to fetch CMS items'
228
+ 'Failed to fetch CMS items',
256
229
  );
257
230
  }
258
231
 
@@ -260,7 +233,7 @@ export async function handleCoreApiRoutes(
260
233
  if (slug && req.method === 'GET') {
261
234
  return await handleRouteError(
262
235
  () => cmsRoutes.handleItemRoute(collection, slug, cmsService),
263
- 'Failed to fetch CMS item'
236
+ 'Failed to fetch CMS item',
264
237
  );
265
238
  }
266
239
  }
@@ -1,6 +1,6 @@
1
1
  import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
2
- import { join } from 'path';
3
- import { mkdirSync, rmSync, writeFileSync } from 'fs';
2
+ import { join } from 'node:path';
3
+ import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
4
4
  import { setProjectRoot, getProjectRoot } from '../../projectContext';
5
5
  import { enumService } from '../../services/EnumService';
6
6
  import { handleEnumsRoute } from './enums';
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import { projectPaths } from '../../projectContext';
10
- import path from 'path';
10
+ import path from 'node:path';
11
11
  import { readTextFile, fileExists } from '../../runtime';
12
12
 
13
13
  /**
@@ -38,8 +38,7 @@ async function loadProjectEnv(): Promise<Record<string, string>> {
38
38
  if (key) {
39
39
  // Remove quotes from value if present
40
40
  let value = valueParts.join('=');
41
- if ((value.startsWith('"') && value.endsWith('"')) ||
42
- (value.startsWith("'") && value.endsWith("'"))) {
41
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
43
42
  value = value.slice(1, -1);
44
43
  }
45
44
  env[key.trim()] = value;
@@ -58,10 +57,7 @@ async function loadProjectEnv(): Promise<Record<string, string>> {
58
57
  * Handle API function requests in development
59
58
  * Routes like /api/contact are mapped to /functions/api/contact.ts
60
59
  */
61
- export async function handleFunctionsRoute(
62
- req: Request,
63
- url: URL
64
- ): Promise<Response | undefined> {
60
+ export async function handleFunctionsRoute(req: Request, url: URL): Promise<Response | undefined> {
65
61
  // Only handle /api/* routes
66
62
  if (!url.pathname.startsWith('/api/')) {
67
63
  return undefined;
@@ -75,11 +71,7 @@ export async function handleFunctionsRoute(
75
71
  // Extract function path from URL
76
72
  // /api/contact -> functions/api/contact.ts
77
73
  const functionPath = url.pathname.replace('/api/', '');
78
- const functionFilePath = path.join(
79
- projectPaths.functions(),
80
- 'api',
81
- `${functionPath}.ts`
82
- );
74
+ const functionFilePath = path.join(projectPaths.functions(), 'api', `${functionPath}.ts`);
83
75
 
84
76
  // Check if function file exists
85
77
  if (!(await fileExists(functionFilePath))) {
@@ -104,10 +96,10 @@ export async function handleFunctionsRoute(
104
96
  const handler = functionModule[handlerName] || functionModule.onRequest;
105
97
 
106
98
  if (!handler || typeof handler !== 'function') {
107
- return new Response(
108
- JSON.stringify({ error: `No handler found for ${method} request` }),
109
- { status: 405, headers: { 'Content-Type': 'application/json' } }
110
- );
99
+ return new Response(JSON.stringify({ error: `No handler found for ${method} request` }), {
100
+ status: 405,
101
+ headers: { 'Content-Type': 'application/json' },
102
+ });
111
103
  }
112
104
 
113
105
  // Load environment variables
@@ -143,7 +135,7 @@ export async function handleFunctionsRoute(
143
135
  error: 'Function execution error',
144
136
  message: error instanceof Error ? error.message : 'Unknown error',
145
137
  }),
146
- { status: 500, headers: { 'Content-Type': 'application/json' } }
138
+ { status: 500, headers: { 'Content-Type': 'application/json' } },
147
139
  );
148
140
  }
149
141
  }
@@ -30,7 +30,7 @@ export async function handleApiRoutes(
30
30
  url: URL,
31
31
  pageService: PageService,
32
32
  componentService: ComponentService,
33
- cmsContext?: CMSRouteContext
33
+ cmsContext?: CMSRouteContext,
34
34
  ): Promise<Response | undefined> {
35
35
  try {
36
36
  const coreContext: CoreRouteContext = {
@@ -42,10 +42,7 @@ export async function handleApiRoutes(
42
42
  return await handleCoreApiRoutes(req, url, coreContext);
43
43
  } catch (error) {
44
44
  // This catch is a fallback - individual routes should handle their own errors
45
- return handleRouteError(
46
- () => Promise.reject(error),
47
- 'API route error'
48
- );
45
+ return handleRouteError(() => Promise.reject(error), 'API route error');
49
46
  }
50
47
  }
51
48
 
@@ -57,7 +54,7 @@ export async function handleCoreOnlyApiRoutes(
57
54
  url: URL,
58
55
  pageService: PageService,
59
56
  componentService: ComponentService,
60
- cmsService?: CMSService
57
+ cmsService?: CMSService,
61
58
  ): Promise<Response | undefined> {
62
59
  const context: CoreRouteContext = {
63
60
  pageService,
@@ -6,6 +6,7 @@
6
6
  import type { PageService } from '../../services/pageService';
7
7
  import { API_ROUTES } from '../../../shared/constants';
8
8
  import { parseJSON } from '../../jsonLoader';
9
+ import { logRuntimeError } from '../../../shared/errorLogger';
9
10
  import { createCorsHeaders } from '../../middleware/cors';
10
11
  import { jsonResponse, cachedJsonResponse } from './shared';
11
12
 
@@ -21,10 +22,7 @@ export function handlePagesRoute(pageService: PageService): Response {
21
22
  /**
22
23
  * Handle page data API endpoint - GET /api/page-data/:path
23
24
  */
24
- export function handlePageDataRoute(
25
- url: URL,
26
- pageService: PageService
27
- ): Response {
25
+ export function handlePageDataRoute(url: URL, pageService: PageService): Response {
28
26
  const pagePath = url.pathname.replace(API_ROUTES.PAGE_DATA, '') || '/';
29
27
  const content = pageService.getPage(pagePath);
30
28
 
@@ -41,7 +39,11 @@ export function handlePageDataRoute(
41
39
  }
42
40
  return jsonResponse({ ...(parsedContent as Record<string, unknown>), _lineMap: lineMapObj });
43
41
  } catch (error) {
44
- return jsonResponse({ error: 'Invalid JSON' }, { status: 500 });
42
+ // The stored page content failed to parse a server-side data-integrity
43
+ // problem (corrupt file / partial write), so this stays a 5xx. Surface the
44
+ // parser message + path instead of an opaque "Invalid JSON".
45
+ logRuntimeError('api.pageData.parse', error, { pagePath });
46
+ return jsonResponse({ error: error instanceof Error ? error.message : 'Invalid JSON' }, { status: 500 });
45
47
  }
46
48
  } else {
47
49
  return jsonResponse({ error: 'Page not found' }, { status: 404 });
@@ -56,11 +58,7 @@ export function handlePageDataRoute(
56
58
  * Uses ETag revalidation so repeat navigations to the same page get a 304
57
59
  * instead of re-transmitting an unchanged body.
58
60
  */
59
- export function handlePageContentRoute(
60
- req: Request,
61
- url: URL,
62
- pageService: PageService
63
- ): Response {
61
+ export function handlePageContentRoute(req: Request, url: URL, pageService: PageService): Response {
64
62
  const page = url.searchParams.get('page') || '/';
65
63
  const content = pageService.getPage(page);
66
64
 
@@ -86,4 +84,3 @@ export function handleSlugMappingsRoute(pageService: PageService): Response {
86
84
  const mappings = pageService.getSlugMappings();
87
85
  return jsonResponse({ mappings });
88
86
  }
89
-
@@ -36,7 +36,7 @@ describe('shared API utilities', () => {
36
36
  const data = {
37
37
  nested: { value: 123 },
38
38
  array: [1, 2, 3],
39
- string: 'hello'
39
+ string: 'hello',
40
40
  };
41
41
  const response = jsonResponse(data);
42
42
  const json = await response.json();
@@ -2,21 +2,25 @@
2
2
  * Shared utilities for API routes
3
3
  */
4
4
 
5
- import { createCorsHeaders } from '../../middleware/cors';
5
+ import { createCorsHeaders, type CorsOptions } from '../../middleware/cors';
6
6
 
7
7
  /**
8
- * Helper function for JSON responses with CORS headers
8
+ * Helper function for JSON responses with CORS headers.
9
+ *
10
+ * `options.cors` lets a caller scope CORS for a sensitive route (e.g. pass a
11
+ * localhost-only `origin` allow-list + the request `Origin`); when omitted the
12
+ * default permissive `*` headers are used, so existing callers are unaffected.
9
13
  */
10
- export function jsonResponse(data: unknown, options: { status?: number } = {}): Response {
11
- const corsHeaders = createCorsHeaders();
14
+ export function jsonResponse(data: unknown, options: { status?: number; cors?: CorsOptions } = {}): Response {
15
+ const corsHeaders = createCorsHeaders(options.cors);
12
16
 
13
17
  return new Response(JSON.stringify(data), {
14
18
  status: options.status || 200,
15
19
  headers: {
16
20
  'Content-Type': 'application/json',
17
21
  'Cache-Control': 'no-store, max-age=0',
18
- 'Pragma': 'no-cache',
19
- 'Expires': '0',
22
+ Pragma: 'no-cache',
23
+ Expires: '0',
20
24
  ...corsHeaders,
21
25
  },
22
26
  });
@@ -65,7 +69,7 @@ export function cachedJsonResponse(
65
69
  return new Response(null, {
66
70
  status: 304,
67
71
  headers: {
68
- 'ETag': etag,
72
+ ETag: etag,
69
73
  'Cache-Control': 'no-cache',
70
74
  ...corsHeaders,
71
75
  },
@@ -76,7 +80,7 @@ export function cachedJsonResponse(
76
80
  status: options.status ?? 200,
77
81
  headers: {
78
82
  'Content-Type': contentType,
79
- 'ETag': etag,
83
+ ETag: etag,
80
84
  // `no-cache` (not `no-store`) — browser may keep the body but must
81
85
  // revalidate every time. Pairs with the 304 branch above.
82
86
  'Cache-Control': 'no-cache',
@@ -84,4 +88,3 @@ export function cachedJsonResponse(
84
88
  },
85
89
  });
86
90
  }
87
-
@@ -1,6 +1,6 @@
1
1
  import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
2
- import { join } from 'path';
3
- import { mkdirSync, rmSync, writeFileSync } from 'fs';
2
+ import { join } from 'node:path';
3
+ import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
4
4
  import { setProjectRoot, getProjectRoot } from '../../projectContext';
5
5
  import { variableService } from '../../services/VariableService';
6
6
  import { handleVariablesStatusRoute, handleVariablesCSSRoute } from './variables';
@@ -9,9 +9,7 @@ import type { VariablesConfig } from '../../../shared/types';
9
9
  const TEST_DIR = join('/tmp', `variablesRoute-test-${process.pid}`);
10
10
 
11
11
  const VALID_CONFIG: VariablesConfig = {
12
- variables: [
13
- { name: 'heading-size', cssVar: '--heading-size', value: '2rem', type: 'fontSize', group: 'font-size' },
14
- ],
12
+ variables: [{ name: 'heading-size', cssVar: '--heading-size', value: '2rem', type: 'fontSize', group: 'font-size' }],
15
13
  };
16
14
 
17
15
  function writeVariables(config: VariablesConfig): void {
@@ -29,6 +29,6 @@ export async function handleVariablesCSSRoute(): Promise<Response> {
29
29
  const responsiveScalesConfig = configService.getResponsiveScales();
30
30
  const css = generateVariablesCSS(variablesConfig, breakpointConfig, responsiveScalesConfig);
31
31
  return new Response(css, {
32
- headers: { 'Content-Type': 'text/css' }
32
+ headers: { 'Content-Type': 'text/css' },
33
33
  });
34
34
  }
@@ -55,8 +55,8 @@ export interface RouteContext {
55
55
  export async function handleRoutes(
56
56
  req: Request,
57
57
  url: URL,
58
- server: any,
59
- context: RouteContext
58
+ _server: any,
59
+ context: RouteContext,
60
60
  ): Promise<Response | undefined> {
61
61
  const startTime = Date.now();
62
62
  const { pageService, componentService, cmsService, cmsProvider } = context;
@@ -96,7 +96,7 @@ export async function handleRoutes(
96
96
  return new Response(null, { status: 204, headers: corsHeaders });
97
97
  }
98
98
  try {
99
- const body = await req.json() as { path?: string; content?: string };
99
+ const body = (await req.json()) as { path?: string; content?: string };
100
100
  if (typeof body.path === 'string' && typeof body.content === 'string' && body.path.startsWith('/')) {
101
101
  store.set(body.path, body.content);
102
102
  // Nudge connected tabs to refetch. The existing live-reload
@@ -116,14 +116,16 @@ export async function handleRoutes(
116
116
  const store = context.draftPageStore;
117
117
  if (store) {
118
118
  try {
119
- const body = await req.json() as { path?: string };
119
+ const body = (await req.json()) as { path?: string };
120
120
  if (typeof body.path === 'string') {
121
121
  store.clear(body.path);
122
122
  // External tabs viewing this path should refetch the disk
123
123
  // version now that the draft is gone.
124
124
  context.wsManager?.broadcastUpdate(body.path);
125
125
  }
126
- } catch { /* ignore */ }
126
+ } catch {
127
+ /* ignore */
128
+ }
127
129
  }
128
130
  logResponseTime(startTime, req);
129
131
  return new Response(null, { status: 204, headers: corsHeaders });
@@ -143,19 +145,10 @@ export async function handleRoutes(
143
145
  }
144
146
 
145
147
  // Build CMS context if CMS service and provider are available
146
- const cmsContext: CMSRouteContext | undefined =
147
- cmsService && cmsProvider
148
- ? { cmsService, cmsProvider }
149
- : undefined;
148
+ const cmsContext: CMSRouteContext | undefined = cmsService && cmsProvider ? { cmsService, cmsProvider } : undefined;
150
149
 
151
150
  // API Routes
152
- const apiResponse = await handleApiRoutes(
153
- req,
154
- url,
155
- pageService,
156
- componentService,
157
- cmsContext
158
- );
151
+ const apiResponse = await handleApiRoutes(req, url, pageService, componentService, cmsContext);
159
152
  if (apiResponse) {
160
153
  logResponseTime(startTime, req);
161
154
  return apiResponse;
@@ -165,7 +158,7 @@ export async function handleRoutes(
165
158
  // Pattern: /data/{collection}/index.json
166
159
  if (url.pathname.startsWith('/data/') && url.pathname.endsWith('/index.json') && cmsService) {
167
160
  const match = url.pathname.match(/^\/data\/([^/]+)\/index\.json$/);
168
- if (match) {
161
+ if (match && match[1] !== undefined) {
169
162
  const collectionId = match[1];
170
163
  try {
171
164
  // Resolve locale to filter draft items
@@ -174,7 +167,9 @@ export async function handleRoutes(
174
167
  try {
175
168
  const referer = req.headers.get('referer');
176
169
  if (referer) refererPath = new URL(referer).pathname;
177
- } catch { /* ignore malformed referer */ }
170
+ } catch {
171
+ /* ignore malformed referer */
172
+ }
178
173
  const { locale } = parseLocaleFromPath(refererPath, i18nConfig);
179
174
  const items = await cmsService.queryItems({ collection: collectionId, excludeDraftLocale: locale });
180
175
  logResponseTime(startTime, req);
@@ -209,7 +204,13 @@ export async function handleRoutes(
209
204
  }
210
205
 
211
206
  // Static asset directories - serve before page routes
212
- if (url.pathname.startsWith('/images/') || url.pathname.startsWith('/videos/') || url.pathname.startsWith('/assets/') || url.pathname.startsWith('/public/') || url.pathname.startsWith('/icons/')) {
207
+ if (
208
+ url.pathname.startsWith('/images/') ||
209
+ url.pathname.startsWith('/videos/') ||
210
+ url.pathname.startsWith('/assets/') ||
211
+ url.pathname.startsWith('/public/') ||
212
+ url.pathname.startsWith('/icons/')
213
+ ) {
213
214
  const response = await handleStaticRoute(url, req);
214
215
  if (response) {
215
216
  logResponseTime(startTime, req);
@@ -223,10 +224,10 @@ export async function handleRoutes(
223
224
  // route wiring look like a working endpoint to API clients.
224
225
  if (url.pathname.startsWith('/api/')) {
225
226
  logResponseTime(startTime, req);
226
- return new Response(
227
- JSON.stringify({ error: 'Not Found', path: url.pathname }),
228
- { status: 404, headers: { 'Content-Type': 'application/json' } }
229
- );
227
+ return new Response(JSON.stringify({ error: 'Not Found', path: url.pathname }), {
228
+ status: 404,
229
+ headers: { 'Content-Type': 'application/json' },
230
+ });
230
231
  }
231
232
 
232
233
  // Page routes (SSR)
@@ -242,10 +243,6 @@ export async function handleRoutes(
242
243
  return response;
243
244
  } catch (error) {
244
245
  logResponseTime(startTime, req);
245
- return handleRouteError(
246
- () => Promise.reject(error),
247
- `Error handling route: ${url.pathname}`
248
- );
246
+ return handleRouteError(() => Promise.reject(error), `Error handling route: ${url.pathname}`);
249
247
  }
250
248
  }
251
-