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
@@ -65,15 +65,65 @@ const mockAuthorItems: CMSItem[] = [
65
65
  ];
66
66
 
67
67
  const mockBlogItems: CMSItem[] = [
68
- { _id: '1', _filename: 'hello-world', _slug: 'hello-world', slug: 'hello-world', title: 'Hello World', content: 'First post', author: 'john-doe' },
69
- { _id: '2', _filename: 'getting-started', _slug: 'getting-started', slug: 'getting-started', title: 'Getting Started', content: 'Guide', author: 'john-doe', relatedPosts: ['hello-world'] },
70
- { _id: '3', _filename: 'advanced-tips', _slug: 'advanced-tips', slug: 'advanced-tips', title: 'Advanced Tips', content: 'Pro tips', author: 'jane-smith', relatedPosts: ['hello-world', 'getting-started'] },
68
+ {
69
+ _id: '1',
70
+ _filename: 'hello-world',
71
+ _slug: 'hello-world',
72
+ slug: 'hello-world',
73
+ title: 'Hello World',
74
+ content: 'First post',
75
+ author: 'john-doe',
76
+ },
77
+ {
78
+ _id: '2',
79
+ _filename: 'getting-started',
80
+ _slug: 'getting-started',
81
+ slug: 'getting-started',
82
+ title: 'Getting Started',
83
+ content: 'Guide',
84
+ author: 'john-doe',
85
+ relatedPosts: ['hello-world'],
86
+ },
87
+ {
88
+ _id: '3',
89
+ _filename: 'advanced-tips',
90
+ _slug: 'advanced-tips',
91
+ slug: 'advanced-tips',
92
+ title: 'Advanced Tips',
93
+ content: 'Pro tips',
94
+ author: 'jane-smith',
95
+ relatedPosts: ['hello-world', 'getting-started'],
96
+ },
71
97
  ];
72
98
 
73
99
  const mockProductItems: CMSItem[] = [
74
- { _id: '1', _filename: 'laptop', slug: 'laptop', name: 'Laptop Pro', price: 999, featured: true, category: 'Electronics' },
75
- { _id: '2', _filename: 'tshirt', slug: 'tshirt', name: 'Cool T-Shirt', price: 29, featured: false, category: 'Clothing' },
76
- { _id: '3', _filename: 'headphones', slug: 'headphones', name: 'Wireless Headphones', price: 199, featured: true, category: 'Electronics' },
100
+ {
101
+ _id: '1',
102
+ _filename: 'laptop',
103
+ slug: 'laptop',
104
+ name: 'Laptop Pro',
105
+ price: 999,
106
+ featured: true,
107
+ category: 'Electronics',
108
+ },
109
+ {
110
+ _id: '2',
111
+ _filename: 'tshirt',
112
+ slug: 'tshirt',
113
+ name: 'Cool T-Shirt',
114
+ price: 29,
115
+ featured: false,
116
+ category: 'Clothing',
117
+ },
118
+ {
119
+ _id: '3',
120
+ _filename: 'headphones',
121
+ slug: 'headphones',
122
+ name: 'Wireless Headphones',
123
+ price: 199,
124
+ featured: true,
125
+ category: 'Electronics',
126
+ },
77
127
  ];
78
128
 
79
129
  describe('CMSService', () => {
@@ -82,11 +132,12 @@ describe('CMSService', () => {
82
132
 
83
133
  beforeEach(async () => {
84
134
  mockProvider = {
85
- getAllSchemas: async () => new Map([
86
- ['authors', mockAuthorSchemaInfo],
87
- ['blog-posts', mockSchemaInfo],
88
- ['products', mockProductSchemaInfo],
89
- ]),
135
+ getAllSchemas: async () =>
136
+ new Map([
137
+ ['authors', mockAuthorSchemaInfo],
138
+ ['blog-posts', mockSchemaInfo],
139
+ ['products', mockProductSchemaInfo],
140
+ ]),
90
141
  getItems: async (collection: string) => {
91
142
  if (collection === 'authors') return mockAuthorItems;
92
143
  if (collection === 'blog-posts') return mockBlogItems;
@@ -95,28 +146,28 @@ describe('CMSService', () => {
95
146
  },
96
147
  getItemBySlug: async (collection: string, slug: string) => {
97
148
  if (collection === 'blog-posts') {
98
- return mockBlogItems.find(i => i.slug === slug) || null;
149
+ return mockBlogItems.find((i) => i.slug === slug) || null;
99
150
  }
100
151
  if (collection === 'products') {
101
- return mockProductItems.find(i => i.slug === slug) || null;
152
+ return mockProductItems.find((i) => i.slug === slug) || null;
102
153
  }
103
154
  return null;
104
155
  },
105
156
  getItemByFilename: async (collection: string, filename: string) => {
106
157
  if (collection === 'blog-posts') {
107
- return mockBlogItems.find(i => i._filename === filename || i.slug === filename) || null;
158
+ return mockBlogItems.find((i) => i._filename === filename || i.slug === filename) || null;
108
159
  }
109
160
  if (collection === 'products') {
110
- return mockProductItems.find(i => i._filename === filename || i.slug === filename) || null;
161
+ return mockProductItems.find((i) => i._filename === filename || i.slug === filename) || null;
111
162
  }
112
163
  return null;
113
164
  },
114
165
  getItemById: async (collection: string, id: string) => {
115
166
  if (collection === 'blog-posts') {
116
- return mockBlogItems.find(i => i._id === id) || null;
167
+ return mockBlogItems.find((i) => i._id === id) || null;
117
168
  }
118
169
  if (collection === 'products') {
119
- return mockProductItems.find(i => i._id === id) || null;
170
+ return mockProductItems.find((i) => i._id === id) || null;
120
171
  }
121
172
  return null;
122
173
  },
@@ -128,7 +179,9 @@ describe('CMSService', () => {
128
179
  hasDraft: async () => false,
129
180
  saveDraft: async () => {},
130
181
  discardDraft: async () => {},
131
- publishDraft: async () => { throw new Error('publishDraft not implemented in default mock'); },
182
+ publishDraft: async () => {
183
+ throw new Error('publishDraft not implemented in default mock');
184
+ },
132
185
  };
133
186
  service = new CMSService(mockProvider);
134
187
  await service.initialize();
@@ -175,7 +228,7 @@ describe('CMSService', () => {
175
228
  expect(match).toEqual({
176
229
  collection: 'blog-posts',
177
230
  slug: 'hello-world',
178
- item: mockBlogItems[0],
231
+ item: mockBlogItems[0]!,
179
232
  pagePath: '/templates/blog-post.json',
180
233
  });
181
234
  });
@@ -185,7 +238,7 @@ describe('CMSService', () => {
185
238
  expect(match).toEqual({
186
239
  collection: 'products',
187
240
  slug: 'laptop',
188
- item: mockProductItems[0],
241
+ item: mockProductItems[0]!,
189
242
  pagePath: '/templates/product.json',
190
243
  });
191
244
  });
@@ -214,20 +267,12 @@ describe('CMSService', () => {
214
267
  describe('getCollectionURLs', () => {
215
268
  it('should return all URLs for blog-posts collection', async () => {
216
269
  const urls = await service.getCollectionURLs('blog-posts');
217
- expect(urls).toEqual([
218
- '/blog/hello-world',
219
- '/blog/getting-started',
220
- '/blog/advanced-tips',
221
- ]);
270
+ expect(urls).toEqual(['/blog/hello-world', '/blog/getting-started', '/blog/advanced-tips']);
222
271
  });
223
272
 
224
273
  it('should return all URLs for products collection', async () => {
225
274
  const urls = await service.getCollectionURLs('products');
226
- expect(urls).toEqual([
227
- '/shop/laptop',
228
- '/shop/tshirt',
229
- '/shop/headphones',
230
- ]);
275
+ expect(urls).toEqual(['/shop/laptop', '/shop/tshirt', '/shop/headphones']);
231
276
  });
232
277
 
233
278
  it('should return empty array for unknown collection', async () => {
@@ -262,7 +307,7 @@ describe('CMSService', () => {
262
307
  filter: { featured: true },
263
308
  });
264
309
  expect(items).toHaveLength(2);
265
- expect(items.every(i => i.featured === true)).toBe(true);
310
+ expect(items.every((i) => i.featured === true)).toBe(true);
266
311
  });
267
312
 
268
313
  it('should apply filter with eq operator', async () => {
@@ -271,7 +316,7 @@ describe('CMSService', () => {
271
316
  filter: { field: 'category', operator: 'eq', value: 'Electronics' },
272
317
  });
273
318
  expect(items).toHaveLength(2);
274
- expect(items.every(i => i.category === 'Electronics')).toBe(true);
319
+ expect(items.every((i) => i.category === 'Electronics')).toBe(true);
275
320
  });
276
321
 
277
322
  it('should apply filter with neq operator', async () => {
@@ -280,7 +325,7 @@ describe('CMSService', () => {
280
325
  filter: { field: 'category', operator: 'neq', value: 'Electronics' },
281
326
  });
282
327
  expect(items).toHaveLength(1);
283
- expect(items[0].category).toBe('Clothing');
328
+ expect(items[0]!.category).toBe('Clothing');
284
329
  });
285
330
 
286
331
  it('should apply filter with gt operator', async () => {
@@ -289,7 +334,7 @@ describe('CMSService', () => {
289
334
  filter: { field: 'price', operator: 'gt', value: 100 },
290
335
  });
291
336
  expect(items).toHaveLength(2);
292
- expect(items.every(i => (i.price as number) > 100)).toBe(true);
337
+ expect(items.every((i) => (i.price as number) > 100)).toBe(true);
293
338
  });
294
339
 
295
340
  it('should apply filter with gte operator', async () => {
@@ -306,7 +351,7 @@ describe('CMSService', () => {
306
351
  filter: { field: 'price', operator: 'lt', value: 100 },
307
352
  });
308
353
  expect(items).toHaveLength(1);
309
- expect(items[0].name).toBe('Cool T-Shirt');
354
+ expect(items[0]!.name).toBe('Cool T-Shirt');
310
355
  });
311
356
 
312
357
  it('should apply filter with lte operator', async () => {
@@ -323,7 +368,7 @@ describe('CMSService', () => {
323
368
  filter: { field: 'name', operator: 'contains', value: 'Wireless' },
324
369
  });
325
370
  expect(items).toHaveLength(1);
326
- expect(items[0].slug).toBe('headphones');
371
+ expect(items[0]!.slug).toBe('headphones');
327
372
  });
328
373
 
329
374
  it('should apply filter with in operator', async () => {
@@ -350,9 +395,9 @@ describe('CMSService', () => {
350
395
  collection: 'products',
351
396
  sort: { field: 'price', order: 'asc' },
352
397
  });
353
- expect(items[0].price).toBe(29);
354
- expect(items[1].price).toBe(199);
355
- expect(items[2].price).toBe(999);
398
+ expect(items[0]!.price).toBe(29);
399
+ expect(items[1]!.price).toBe(199);
400
+ expect(items[2]!.price).toBe(999);
356
401
  });
357
402
 
358
403
  it('should apply descending sort', async () => {
@@ -360,9 +405,9 @@ describe('CMSService', () => {
360
405
  collection: 'products',
361
406
  sort: { field: 'price', order: 'desc' },
362
407
  });
363
- expect(items[0].price).toBe(999);
364
- expect(items[1].price).toBe(199);
365
- expect(items[2].price).toBe(29);
408
+ expect(items[0]!.price).toBe(999);
409
+ expect(items[1]!.price).toBe(199);
410
+ expect(items[2]!.price).toBe(29);
366
411
  });
367
412
 
368
413
  it('should apply multi-field sort', async () => {
@@ -374,9 +419,9 @@ describe('CMSService', () => {
374
419
  ],
375
420
  });
376
421
  // Featured items first (true > false), then by price ascending
377
- expect(items[0].slug).toBe('headphones'); // featured=true, price=199
378
- expect(items[1].slug).toBe('laptop'); // featured=true, price=999
379
- expect(items[2].slug).toBe('tshirt'); // featured=false, price=29
422
+ expect(items[0]!.slug).toBe('headphones'); // featured=true, price=199
423
+ expect(items[1]!.slug).toBe('laptop'); // featured=true, price=999
424
+ expect(items[2]!.slug).toBe('tshirt'); // featured=false, price=29
380
425
  });
381
426
 
382
427
  it('should apply limit', async () => {
@@ -393,7 +438,7 @@ describe('CMSService', () => {
393
438
  offset: 1,
394
439
  });
395
440
  expect(items).toHaveLength(2);
396
- expect(items[0].slug).toBe('tshirt');
441
+ expect(items[0]!.slug).toBe('tshirt');
397
442
  });
398
443
 
399
444
  it('should apply limit and offset together', async () => {
@@ -404,7 +449,7 @@ describe('CMSService', () => {
404
449
  limit: 1,
405
450
  });
406
451
  expect(items).toHaveLength(1);
407
- expect(items[0].price).toBe(199);
452
+ expect(items[0]!.price).toBe(199);
408
453
  });
409
454
 
410
455
  it('should return empty array for empty collection', async () => {
@@ -432,23 +477,23 @@ describe('CMSService', () => {
432
477
  it('should return items matching IDs in order', async () => {
433
478
  const items = await service.getItemsByIds('blog-posts', ['2', '1', '3']);
434
479
  expect(items).toHaveLength(3);
435
- expect(items[0]._id).toBe('2');
436
- expect(items[1]._id).toBe('1');
437
- expect(items[2]._id).toBe('3');
480
+ expect(items[0]!._id).toBe('2');
481
+ expect(items[1]!._id).toBe('1');
482
+ expect(items[2]!._id).toBe('3');
438
483
  });
439
484
 
440
485
  it('should support _filename lookup', async () => {
441
486
  const items = await service.getItemsByIds('blog-posts', ['hello-world', 'advanced-tips']);
442
487
  expect(items).toHaveLength(2);
443
- expect(items[0]._filename).toBe('hello-world');
444
- expect(items[1]._filename).toBe('advanced-tips');
488
+ expect(items[0]!._filename).toBe('hello-world');
489
+ expect(items[1]!._filename).toBe('advanced-tips');
445
490
  });
446
491
 
447
492
  it('should filter out non-existent IDs', async () => {
448
493
  const items = await service.getItemsByIds('blog-posts', ['1', 'non-existent', '2']);
449
494
  expect(items).toHaveLength(2);
450
- expect(items[0]._id).toBe('1');
451
- expect(items[1]._id).toBe('2');
495
+ expect(items[0]!._id).toBe('1');
496
+ expect(items[1]!._id).toBe('2');
452
497
  });
453
498
 
454
499
  it('should return empty array for empty input', async () => {
@@ -459,9 +504,9 @@ describe('CMSService', () => {
459
504
  it('should handle mixed _id and _filename lookups', async () => {
460
505
  const items = await service.getItemsByIds('blog-posts', ['1', 'getting-started', '3']);
461
506
  expect(items).toHaveLength(3);
462
- expect(items[0]._id).toBe('1');
463
- expect(items[1]._filename).toBe('getting-started');
464
- expect(items[2]._id).toBe('3');
507
+ expect(items[0]!._id).toBe('1');
508
+ expect(items[1]!._filename).toBe('getting-started');
509
+ expect(items[2]!._id).toBe('3');
465
510
  });
466
511
 
467
512
  it('should return empty array for unknown collection', async () => {
@@ -480,24 +525,24 @@ describe('CMSService', () => {
480
525
  // john-doe is referenced by 2 blog posts via 'author' field
481
526
  const refs = await service.findReferencesTo('authors', 'john-doe');
482
527
  expect(refs).toHaveLength(2);
483
- expect(refs[0].collection).toBe('blog-posts');
484
- expect(refs[0].fieldName).toBe('author');
485
- expect(refs[0].itemFilename).toBe('hello-world');
486
- expect(refs[1].itemFilename).toBe('getting-started');
528
+ expect(refs[0]!.collection).toBe('blog-posts');
529
+ expect(refs[0]!.fieldName).toBe('author');
530
+ expect(refs[0]!.itemFilename).toBe('hello-world');
531
+ expect(refs[1]!.itemFilename).toBe('getting-started');
487
532
  });
488
533
 
489
534
  it('should find references in multi-reference fields', async () => {
490
535
  // hello-world is referenced by 2 posts via 'relatedPosts' field
491
536
  const refs = await service.findReferencesTo('blog-posts', 'hello-world');
492
537
  expect(refs).toHaveLength(2);
493
- expect(refs.every(r => r.fieldName === 'relatedPosts')).toBe(true);
538
+ expect(refs.every((r) => r.fieldName === 'relatedPosts')).toBe(true);
494
539
  });
495
540
 
496
541
  it('should return empty array when no references exist', async () => {
497
542
  // jane-smith is only referenced by advanced-tips
498
543
  const refs = await service.findReferencesTo('authors', 'jane-smith');
499
544
  expect(refs).toHaveLength(1);
500
- expect(refs[0].itemFilename).toBe('advanced-tips');
545
+ expect(refs[0]!.itemFilename).toBe('advanced-tips');
501
546
  });
502
547
 
503
548
  it('should return empty array for non-existent item', async () => {
@@ -510,12 +555,12 @@ describe('CMSService', () => {
510
555
  // but not products (which has no reference fields to authors)
511
556
  const refs = await service.findReferencesTo('authors', 'john-doe');
512
557
  // All references should be from blog-posts, not products
513
- expect(refs.every(r => r.collection === 'blog-posts')).toBe(true);
558
+ expect(refs.every((r) => r.collection === 'blog-posts')).toBe(true);
514
559
  });
515
560
 
516
561
  it('should include item metadata in results', async () => {
517
562
  const refs = await service.findReferencesTo('authors', 'john-doe');
518
- const firstRef = refs[0];
563
+ const firstRef = refs[0]!;
519
564
  expect(firstRef.itemId).toBe('1');
520
565
  expect(firstRef.itemFilename).toBe('hello-world');
521
566
  expect(firstRef.itemSlug).toBe('hello-world');
@@ -543,8 +588,8 @@ describe('CMSService', () => {
543
588
  expect(savedItems).toHaveLength(2);
544
589
 
545
590
  // Both items should have author set to null
546
- expect(savedItems[0].item.author).toBeNull();
547
- expect(savedItems[1].item.author).toBeNull();
591
+ expect(savedItems[0]!.item.author).toBeNull();
592
+ expect(savedItems[1]!.item.author).toBeNull();
548
593
  });
549
594
 
550
595
  it('should filter multi-reference arrays', async () => {
@@ -554,11 +599,11 @@ describe('CMSService', () => {
554
599
  expect(removedCount).toBe(2);
555
600
 
556
601
  // getting-started had ['hello-world'] -> should become null (empty array)
557
- const gettingStarted = savedItems.find(s => s.item._filename === 'getting-started');
602
+ const gettingStarted = savedItems.find((s) => s.item._filename === 'getting-started');
558
603
  expect(gettingStarted?.item.relatedPosts).toBeNull();
559
604
 
560
605
  // advanced-tips had ['hello-world', 'getting-started'] -> should become ['getting-started']
561
- const advancedTips = savedItems.find(s => s.item._filename === 'advanced-tips');
606
+ const advancedTips = savedItems.find((s) => s.item._filename === 'advanced-tips');
562
607
  expect(advancedTips?.item.relatedPosts).toEqual(['getting-started']);
563
608
  });
564
609
 
@@ -566,7 +611,7 @@ describe('CMSService', () => {
566
611
  // getting-started has relatedPosts: ['hello-world'] - when hello-world is removed, should be null
567
612
  await service.removeReferencesTo('blog-posts', 'hello-world');
568
613
 
569
- const gettingStarted = savedItems.find(s => s.item._filename === 'getting-started');
614
+ const gettingStarted = savedItems.find((s) => s.item._filename === 'getting-started');
570
615
  // Empty array should become null, not []
571
616
  expect(gettingStarted?.item.relatedPosts).toBeNull();
572
617
  });
@@ -593,7 +638,7 @@ describe('CMSService', () => {
593
638
  it('should preserve other item fields', async () => {
594
639
  await service.removeReferencesTo('authors', 'john-doe');
595
640
 
596
- const helloWorld = savedItems.find(s => s.item._filename === 'hello-world');
641
+ const helloWorld = savedItems.find((s) => s.item._filename === 'hello-world');
597
642
  expect(helloWorld?.item._id).toBe('1');
598
643
  expect(helloWorld?.item._filename).toBe('hello-world');
599
644
  expect(helloWorld?.item.title).toBe('Hello World');
@@ -653,7 +698,9 @@ describe('CMSService', () => {
653
698
  hasDraft: async () => false,
654
699
  saveDraft: async () => {},
655
700
  discardDraft: async () => {},
656
- publishDraft: async () => { throw new Error('not implemented'); },
701
+ publishDraft: async () => {
702
+ throw new Error('not implemented');
703
+ },
657
704
  };
658
705
 
659
706
  const richService = new CMSService(richTextProvider);
@@ -662,7 +709,7 @@ describe('CMSService', () => {
662
709
  const items = await richService.queryItems({ collection: 'articles' });
663
710
 
664
711
  expect(items).toHaveLength(1);
665
- const item = items[0];
712
+ const item = items[0]!;
666
713
 
667
714
  // Content should be converted to __richtext__ marker
668
715
  expect(item.content).toBeDefined();
@@ -708,14 +755,16 @@ describe('CMSService', () => {
708
755
  hasDraft: async () => false,
709
756
  saveDraft: async () => {},
710
757
  discardDraft: async () => {},
711
- publishDraft: async () => { throw new Error('not implemented'); },
758
+ publishDraft: async () => {
759
+ throw new Error('not implemented');
760
+ },
712
761
  };
713
762
 
714
763
  const svc = new CMSService(provider);
715
764
  await svc.initialize();
716
765
 
717
766
  const items = await svc.queryItems({ collection: 'articles' });
718
- const item = items[0];
767
+ const item = items[0]!;
719
768
 
720
769
  expect((item.content as Record<string, unknown>).__richtext__).toBe(true);
721
770
  expect((item.content as Record<string, unknown>).html).toBe('<p>Already HTML</p>');
@@ -736,9 +785,7 @@ describe('CMSService', () => {
736
785
  pagePath: '/templates/article.json',
737
786
  };
738
787
 
739
- const mockItems: CMSItem[] = [
740
- { _id: '1', _filename: 'test', slug: 'test', summary: 'Plain text summary' },
741
- ];
788
+ const mockItems: CMSItem[] = [{ _id: '1', _filename: 'test', slug: 'test', summary: 'Plain text summary' }];
742
789
 
743
790
  const provider: CMSProvider = {
744
791
  getAllSchemas: async () => new Map([['articles', schemaInfo]]),
@@ -753,7 +800,9 @@ describe('CMSService', () => {
753
800
  hasDraft: async () => false,
754
801
  saveDraft: async () => {},
755
802
  discardDraft: async () => {},
756
- publishDraft: async () => { throw new Error('not implemented'); },
803
+ publishDraft: async () => {
804
+ throw new Error('not implemented');
805
+ },
757
806
  };
758
807
 
759
808
  const svc = new CMSService(provider);
@@ -761,7 +810,7 @@ describe('CMSService', () => {
761
810
 
762
811
  const items = await svc.queryItems({ collection: 'articles' });
763
812
  // Regular text field should remain unchanged
764
- expect(items[0].summary).toBe('Plain text summary');
813
+ expect(items[0]!.summary).toBe('Plain text summary');
765
814
  });
766
815
 
767
816
  it('should skip null/undefined richtext fields', async () => {
@@ -797,39 +846,37 @@ describe('CMSService', () => {
797
846
  hasDraft: async () => false,
798
847
  saveDraft: async () => {},
799
848
  discardDraft: async () => {},
800
- publishDraft: async () => { throw new Error('not implemented'); },
849
+ publishDraft: async () => {
850
+ throw new Error('not implemented');
851
+ },
801
852
  };
802
853
 
803
854
  const svc = new CMSService(provider);
804
855
  await svc.initialize();
805
856
 
806
857
  const items = await svc.queryItems({ collection: 'articles' });
807
- expect(items[0].content).toBeNull();
808
- expect(items[1].content).toBeUndefined();
858
+ expect(items[0]!.content).toBeNull();
859
+ expect(items[1]!.content).toBeUndefined();
809
860
  });
810
861
  });
811
862
 
812
863
  describe('drafts', () => {
813
- function makeService(opts: {
814
- published?: CMSItem[];
815
- drafts?: CMSItem[];
816
- }): CMSService {
864
+ function makeService(opts: { published?: CMSItem[]; drafts?: CMSItem[] }): CMSService {
817
865
  const published = opts.published ?? [];
818
866
  const drafts = opts.drafts ?? [];
819
- const findByFilename = (list: CMSItem[], f: string) =>
820
- list.find(i => i._filename === f) || null;
867
+ const findByFilename = (list: CMSItem[], f: string) => list.find((i) => i._filename === f) || null;
821
868
 
822
869
  const provider: CMSProvider = {
823
870
  getAllSchemas: async () => new Map([['blog-posts', mockSchemaInfo]]),
824
871
  getItems: async () => published,
825
872
  getItemBySlug: async (_c, s) => findByFilename(published, s),
826
873
  getItemByFilename: async (_c, f) => findByFilename(published, f),
827
- getItemById: async (_c, id) => published.find(i => i._id === id) ?? null,
874
+ getItemById: async (_c, id) => published.find((i) => i._id === id) ?? null,
828
875
  saveItem: async () => {},
829
876
  deleteItem: async () => {},
830
877
  getDraft: async (_c, f) => findByFilename(drafts, f),
831
878
  getAllDrafts: async () => drafts,
832
- hasDraft: async (_c, f) => drafts.some(d => d._filename === f),
879
+ hasDraft: async (_c, f) => drafts.some((d) => d._filename === f),
833
880
  saveDraft: async () => {},
834
881
  discardDraft: async () => {},
835
882
  publishDraft: async (_c, f) => {
@@ -870,15 +917,13 @@ describe('CMSService', () => {
870
917
  { _id: '1', _filename: 'hello', slug: 'hello', title: 'Hello' },
871
918
  { _id: '2', _filename: 'second', slug: 'second', title: 'Second' },
872
919
  ],
873
- drafts: [
874
- { _id: '1', _filename: 'hello', slug: 'hello', title: 'Hello (WIP)', _isDraft: true },
875
- ],
920
+ drafts: [{ _id: '1', _filename: 'hello', slug: 'hello', title: 'Hello (WIP)', _isDraft: true }],
876
921
  });
877
922
  await svc.initialize();
878
923
  const list = await svc.listItemsWithDraftFlag('blog-posts');
879
924
  expect(list).toHaveLength(2);
880
- const hello = list.find(i => i._filename === 'hello');
881
- const second = list.find(i => i._filename === 'second');
925
+ const hello = list.find((i) => i._filename === 'hello');
926
+ const second = list.find((i) => i._filename === 'second');
882
927
  expect(hello?._hasDraft).toBe(true);
883
928
  expect(second?._hasDraft).toBeUndefined();
884
929
  });
@@ -886,28 +931,24 @@ describe('CMSService', () => {
886
931
  it('listItemsWithDraftFlag includes draft-only items at end', async () => {
887
932
  const svc = makeService({
888
933
  published: [{ _id: '1', _filename: 'hello', slug: 'hello', title: 'Hello' }],
889
- drafts: [
890
- { _id: 'new', _filename: 'brand-new', slug: 'brand-new', title: 'New', _isDraft: true },
891
- ],
934
+ drafts: [{ _id: 'new', _filename: 'brand-new', slug: 'brand-new', title: 'New', _isDraft: true }],
892
935
  });
893
936
  await svc.initialize();
894
937
  const list = await svc.listItemsWithDraftFlag('blog-posts');
895
938
  expect(list).toHaveLength(2);
896
- const draftOnly = list.find(i => i._filename === 'brand-new');
939
+ const draftOnly = list.find((i) => i._filename === 'brand-new');
897
940
  expect(draftOnly?._isDraft).toBe(true);
898
941
  });
899
942
 
900
943
  it('queryItems is unaffected by drafts (still published-only)', async () => {
901
944
  const svc = makeService({
902
945
  published: [{ _id: '1', _filename: 'hello', slug: 'hello', title: 'Hello' }],
903
- drafts: [
904
- { _id: 'new', _filename: 'brand-new', slug: 'brand-new', title: 'New', _isDraft: true },
905
- ],
946
+ drafts: [{ _id: 'new', _filename: 'brand-new', slug: 'brand-new', title: 'New', _isDraft: true }],
906
947
  });
907
948
  await svc.initialize();
908
949
  const items = await svc.queryItems({ collection: 'blog-posts' });
909
950
  expect(items).toHaveLength(1);
910
- expect(items[0]._filename).toBe('hello');
951
+ expect(items[0]!._filename).toBe('hello');
911
952
  });
912
953
 
913
954
  it('publishDraft delegates to provider and invalidates cache', async () => {
@@ -922,30 +963,27 @@ describe('CMSService', () => {
922
963
  });
923
964
 
924
965
  describe('preview mode', () => {
925
- function makeService(opts: {
926
- previewMode?: boolean;
927
- published?: CMSItem[];
928
- drafts?: CMSItem[];
929
- }): CMSService {
966
+ function makeService(opts: { previewMode?: boolean; published?: CMSItem[]; drafts?: CMSItem[] }): CMSService {
930
967
  const published = opts.published ?? [];
931
968
  const drafts = opts.drafts ?? [];
932
- const findByFilename = (list: CMSItem[], f: string) =>
933
- list.find(i => i._filename === f) || null;
969
+ const findByFilename = (list: CMSItem[], f: string) => list.find((i) => i._filename === f) || null;
934
970
 
935
971
  const provider: CMSProvider = {
936
972
  getAllSchemas: async () => new Map([['blog-posts', mockSchemaInfo]]),
937
973
  getItems: async () => published,
938
974
  getItemBySlug: async (_c, s) => findByFilename(published, s),
939
975
  getItemByFilename: async (_c, f) => findByFilename(published, f),
940
- getItemById: async (_c, id) => published.find(i => i._id === id) ?? null,
976
+ getItemById: async (_c, id) => published.find((i) => i._id === id) ?? null,
941
977
  saveItem: async () => {},
942
978
  deleteItem: async () => {},
943
979
  getDraft: async (_c, f) => findByFilename(drafts, f),
944
980
  getAllDrafts: async () => drafts,
945
- hasDraft: async (_c, f) => drafts.some(d => d._filename === f),
981
+ hasDraft: async (_c, f) => drafts.some((d) => d._filename === f),
946
982
  saveDraft: async () => {},
947
983
  discardDraft: async () => {},
948
- publishDraft: async () => { throw new Error('not used'); },
984
+ publishDraft: async () => {
985
+ throw new Error('not used');
986
+ },
949
987
  };
950
988
  return new CMSService(provider, { previewMode: opts.previewMode });
951
989
  }
@@ -959,8 +997,8 @@ describe('CMSService', () => {
959
997
  await svc.initialize();
960
998
  const items = await svc.queryItems({ collection: 'blog-posts' });
961
999
  expect(items).toHaveLength(1);
962
- expect(items[0].title).toBe('Hello (WIP)');
963
- expect(items[0]._isDraft).toBe(true);
1000
+ expect(items[0]!.title).toBe('Hello (WIP)');
1001
+ expect(items[0]!._isDraft).toBe(true);
964
1002
  });
965
1003
 
966
1004
  it('queryItems includes draft-only items in preview mode', async () => {
@@ -972,7 +1010,7 @@ describe('CMSService', () => {
972
1010
  await svc.initialize();
973
1011
  const items = await svc.queryItems({ collection: 'blog-posts' });
974
1012
  expect(items).toHaveLength(2);
975
- expect(items.find(i => i._filename === 'brand-new')?._isDraft).toBe(true);
1013
+ expect(items.find((i) => i._filename === 'brand-new')?._isDraft).toBe(true);
976
1014
  });
977
1015
 
978
1016
  it('getItemsByIds merges drafts in preview mode', async () => {
@@ -1003,7 +1041,7 @@ describe('CMSService', () => {
1003
1041
  expect(versions.draft?.title).toBe('Hello (WIP)');
1004
1042
 
1005
1043
  const list = await svc.listItemsWithDraftFlag('blog-posts');
1006
- const item = list.find(i => i._filename === 'hello');
1044
+ const item = list.find((i) => i._filename === 'hello');
1007
1045
  expect(item?.title).toBe('Hello');
1008
1046
  expect(item?._hasDraft).toBe(true);
1009
1047
  });
@@ -1019,8 +1057,8 @@ describe('CMSService', () => {
1019
1057
  await svc.initialize();
1020
1058
  const items = await svc.queryItems({ collection: 'blog-posts' });
1021
1059
  expect(items).toHaveLength(1);
1022
- expect(items[0].title).toBe('Hello');
1023
- expect(items[0]._isDraft).toBeUndefined();
1060
+ expect(items[0]!.title).toBe('Hello');
1061
+ expect(items[0]!._isDraft).toBeUndefined();
1024
1062
  });
1025
1063
  });
1026
1064
  });