@endora-commerce/mod-cms 0.0.0-stage → 0.100.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 (264) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +65 -2
  3. package/dist/admin/api/cms-client.d.ts +77 -0
  4. package/dist/admin/api/cms-client.d.ts.map +1 -0
  5. package/dist/admin/api/cms-client.js +162 -0
  6. package/dist/admin/api/cms-client.js.map +1 -0
  7. package/dist/admin/components/AdminCatalogPreviewProvider.d.ts +6 -0
  8. package/dist/admin/components/AdminCatalogPreviewProvider.d.ts.map +1 -0
  9. package/dist/admin/components/AdminCatalogPreviewProvider.js +74 -0
  10. package/dist/admin/components/AdminCatalogPreviewProvider.js.map +1 -0
  11. package/dist/admin/components/AdminCmsAssetProvider.d.ts +9 -0
  12. package/dist/admin/components/AdminCmsAssetProvider.d.ts.map +1 -0
  13. package/dist/admin/components/AdminCmsAssetProvider.js +50 -0
  14. package/dist/admin/components/AdminCmsAssetProvider.js.map +1 -0
  15. package/dist/admin/components/BackgroundFields.d.ts +4 -0
  16. package/dist/admin/components/BackgroundFields.d.ts.map +1 -0
  17. package/dist/admin/components/BackgroundFields.js +40 -0
  18. package/dist/admin/components/BackgroundFields.js.map +1 -0
  19. package/dist/admin/components/ButtonLinkFields.d.ts +6 -0
  20. package/dist/admin/components/ButtonLinkFields.d.ts.map +1 -0
  21. package/dist/admin/components/ButtonLinkFields.js +127 -0
  22. package/dist/admin/components/ButtonLinkFields.js.map +1 -0
  23. package/dist/admin/components/CarouselPreviewNav.d.ts +12 -0
  24. package/dist/admin/components/CarouselPreviewNav.d.ts.map +1 -0
  25. package/dist/admin/components/CarouselPreviewNav.js +31 -0
  26. package/dist/admin/components/CarouselPreviewNav.js.map +1 -0
  27. package/dist/admin/components/CmsContentEditorLayout.d.ts +12 -0
  28. package/dist/admin/components/CmsContentEditorLayout.d.ts.map +1 -0
  29. package/dist/admin/components/CmsContentEditorLayout.js +9 -0
  30. package/dist/admin/components/CmsContentEditorLayout.js.map +1 -0
  31. package/dist/admin/components/ComponentDragHandle.d.ts +6 -0
  32. package/dist/admin/components/ComponentDragHandle.d.ts.map +1 -0
  33. package/dist/admin/components/ComponentDragHandle.js +119 -0
  34. package/dist/admin/components/ComponentDragHandle.js.map +1 -0
  35. package/dist/admin/components/ContentSliderActionBarExtras.d.ts +6 -0
  36. package/dist/admin/components/ContentSliderActionBarExtras.d.ts.map +1 -0
  37. package/dist/admin/components/ContentSliderActionBarExtras.js +109 -0
  38. package/dist/admin/components/ContentSliderActionBarExtras.js.map +1 -0
  39. package/dist/admin/components/HookBlockAttachmentsPanel.d.ts +9 -0
  40. package/dist/admin/components/HookBlockAttachmentsPanel.d.ts.map +1 -0
  41. package/dist/admin/components/HookBlockAttachmentsPanel.js +137 -0
  42. package/dist/admin/components/HookBlockAttachmentsPanel.js.map +1 -0
  43. package/dist/admin/components/PageBuilderActionBar.d.ts +10 -0
  44. package/dist/admin/components/PageBuilderActionBar.d.ts.map +1 -0
  45. package/dist/admin/components/PageBuilderActionBar.js +118 -0
  46. package/dist/admin/components/PageBuilderActionBar.js.map +1 -0
  47. package/dist/admin/components/PageBuilderDrawer.d.ts +16 -0
  48. package/dist/admin/components/PageBuilderDrawer.d.ts.map +1 -0
  49. package/dist/admin/components/PageBuilderDrawer.js +53 -0
  50. package/dist/admin/components/PageBuilderDrawer.js.map +1 -0
  51. package/dist/admin/components/PageBuilderEditor.d.ts +45 -0
  52. package/dist/admin/components/PageBuilderEditor.d.ts.map +1 -0
  53. package/dist/admin/components/PageBuilderEditor.js +632 -0
  54. package/dist/admin/components/PageBuilderEditor.js.map +1 -0
  55. package/dist/admin/components/PuckActionGuard.d.ts +12 -0
  56. package/dist/admin/components/PuckActionGuard.d.ts.map +1 -0
  57. package/dist/admin/components/PuckActionGuard.js +30 -0
  58. package/dist/admin/components/PuckActionGuard.js.map +1 -0
  59. package/dist/admin/components/RowLayoutPicker.d.ts +8 -0
  60. package/dist/admin/components/RowLayoutPicker.d.ts.map +1 -0
  61. package/dist/admin/components/RowLayoutPicker.js +17 -0
  62. package/dist/admin/components/RowLayoutPicker.js.map +1 -0
  63. package/dist/admin/components/SliderPreviewActionBarExtras.d.ts +6 -0
  64. package/dist/admin/components/SliderPreviewActionBarExtras.d.ts.map +1 -0
  65. package/dist/admin/components/SliderPreviewActionBarExtras.js +32 -0
  66. package/dist/admin/components/SliderPreviewActionBarExtras.js.map +1 -0
  67. package/dist/admin/components/admin-catalog-preview-map.d.ts +17 -0
  68. package/dist/admin/components/admin-catalog-preview-map.d.ts.map +1 -0
  69. package/dist/admin/components/admin-catalog-preview-map.js +18 -0
  70. package/dist/admin/components/admin-catalog-preview-map.js.map +1 -0
  71. package/dist/admin/components/build-viewports.d.ts +23 -0
  72. package/dist/admin/components/build-viewports.d.ts.map +1 -0
  73. package/dist/admin/components/build-viewports.js +23 -0
  74. package/dist/admin/components/build-viewports.js.map +1 -0
  75. package/dist/admin/components/cms-template-layout.d.ts +16 -0
  76. package/dist/admin/components/cms-template-layout.d.ts.map +1 -0
  77. package/dist/admin/components/cms-template-layout.js +53 -0
  78. package/dist/admin/components/cms-template-layout.js.map +1 -0
  79. package/dist/admin/components/page-builder-i18n.d.ts +27 -0
  80. package/dist/admin/components/page-builder-i18n.d.ts.map +1 -0
  81. package/dist/admin/components/page-builder-i18n.js +34 -0
  82. package/dist/admin/components/page-builder-i18n.js.map +1 -0
  83. package/dist/admin/components/puck-safe.d.ts +10 -0
  84. package/dist/admin/components/puck-safe.d.ts.map +1 -0
  85. package/dist/admin/components/puck-safe.js +22 -0
  86. package/dist/admin/components/puck-safe.js.map +1 -0
  87. package/dist/admin/components/scope-utils.d.ts +4 -0
  88. package/dist/admin/components/scope-utils.d.ts.map +1 -0
  89. package/dist/admin/components/scope-utils.js +7 -0
  90. package/dist/admin/components/scope-utils.js.map +1 -0
  91. package/dist/admin/editors/BlockEditor.d.ts +9 -0
  92. package/dist/admin/editors/BlockEditor.d.ts.map +1 -0
  93. package/dist/admin/editors/BlockEditor.js +217 -0
  94. package/dist/admin/editors/BlockEditor.js.map +1 -0
  95. package/dist/admin/editors/PageEditor.d.ts +9 -0
  96. package/dist/admin/editors/PageEditor.d.ts.map +1 -0
  97. package/dist/admin/editors/PageEditor.js +316 -0
  98. package/dist/admin/editors/PageEditor.js.map +1 -0
  99. package/dist/admin/editors/TemplateEditor.d.ts +9 -0
  100. package/dist/admin/editors/TemplateEditor.d.ts.map +1 -0
  101. package/dist/admin/editors/TemplateEditor.js +180 -0
  102. package/dist/admin/editors/TemplateEditor.js.map +1 -0
  103. package/dist/admin/index.d.ts +38 -0
  104. package/dist/admin/index.d.ts.map +1 -0
  105. package/dist/admin/index.js +144 -0
  106. package/dist/admin/index.js.map +1 -0
  107. package/dist/admin/pages/BlocksListPage.d.ts +9 -0
  108. package/dist/admin/pages/BlocksListPage.d.ts.map +1 -0
  109. package/dist/admin/pages/BlocksListPage.js +47 -0
  110. package/dist/admin/pages/BlocksListPage.js.map +1 -0
  111. package/dist/admin/pages/HooksPage.d.ts +9 -0
  112. package/dist/admin/pages/HooksPage.d.ts.map +1 -0
  113. package/dist/admin/pages/HooksPage.js +41 -0
  114. package/dist/admin/pages/HooksPage.js.map +1 -0
  115. package/dist/admin/pages/PagesListPage.d.ts +9 -0
  116. package/dist/admin/pages/PagesListPage.d.ts.map +1 -0
  117. package/dist/admin/pages/PagesListPage.js +51 -0
  118. package/dist/admin/pages/PagesListPage.js.map +1 -0
  119. package/dist/admin/pages/TemplatesListPage.d.ts +9 -0
  120. package/dist/admin/pages/TemplatesListPage.d.ts.map +1 -0
  121. package/dist/admin/pages/TemplatesListPage.js +47 -0
  122. package/dist/admin/pages/TemplatesListPage.js.map +1 -0
  123. package/dist/admin-ui/index.d.ts +90 -0
  124. package/dist/admin-ui/index.d.ts.map +1 -0
  125. package/dist/admin-ui/index.js +89 -0
  126. package/dist/admin-ui/index.js.map +1 -0
  127. package/dist/backend/cli/block-names.d.ts +92 -0
  128. package/dist/backend/cli/block-names.d.ts.map +1 -0
  129. package/dist/backend/cli/block-names.js +132 -0
  130. package/dist/backend/cli/block-names.js.map +1 -0
  131. package/dist/backend/entities/cms-block.entity.d.ts +20 -0
  132. package/dist/backend/entities/cms-block.entity.d.ts.map +1 -0
  133. package/dist/backend/entities/cms-block.entity.js +77 -0
  134. package/dist/backend/entities/cms-block.entity.js.map +1 -0
  135. package/dist/backend/entities/cms-hook-block-attachment.entity.d.ts +15 -0
  136. package/dist/backend/entities/cms-hook-block-attachment.entity.d.ts.map +1 -0
  137. package/dist/backend/entities/cms-hook-block-attachment.entity.js +46 -0
  138. package/dist/backend/entities/cms-hook-block-attachment.entity.js.map +1 -0
  139. package/dist/backend/entities/cms-hook.entity.d.ts +20 -0
  140. package/dist/backend/entities/cms-hook.entity.d.ts.map +1 -0
  141. package/dist/backend/entities/cms-hook.entity.js +73 -0
  142. package/dist/backend/entities/cms-hook.entity.js.map +1 -0
  143. package/dist/backend/entities/cms-page.entity.d.ts +43 -0
  144. package/dist/backend/entities/cms-page.entity.d.ts.map +1 -0
  145. package/dist/backend/entities/cms-page.entity.js +140 -0
  146. package/dist/backend/entities/cms-page.entity.js.map +1 -0
  147. package/dist/backend/entities/cms-template.entity.d.ts +20 -0
  148. package/dist/backend/entities/cms-template.entity.d.ts.map +1 -0
  149. package/dist/backend/entities/cms-template.entity.js +73 -0
  150. package/dist/backend/entities/cms-template.entity.js.map +1 -0
  151. package/dist/backend/index.d.ts +157 -0
  152. package/dist/backend/index.d.ts.map +1 -0
  153. package/dist/backend/index.js +317 -0
  154. package/dist/backend/index.js.map +1 -0
  155. package/dist/backend/plugin.d.ts +81 -0
  156. package/dist/backend/plugin.d.ts.map +1 -0
  157. package/dist/backend/plugin.js +81 -0
  158. package/dist/backend/plugin.js.map +1 -0
  159. package/dist/backend/routes.admin.d.ts +19 -0
  160. package/dist/backend/routes.admin.d.ts.map +1 -0
  161. package/dist/backend/routes.admin.js +164 -0
  162. package/dist/backend/routes.admin.js.map +1 -0
  163. package/dist/backend/routes.storefront.d.ts +6 -0
  164. package/dist/backend/routes.storefront.d.ts.map +1 -0
  165. package/dist/backend/routes.storefront.js +89 -0
  166. package/dist/backend/routes.storefront.js.map +1 -0
  167. package/dist/backend/services/asset-embed-resolver.d.ts +17 -0
  168. package/dist/backend/services/asset-embed-resolver.d.ts.map +1 -0
  169. package/dist/backend/services/asset-embed-resolver.js +40 -0
  170. package/dist/backend/services/asset-embed-resolver.js.map +1 -0
  171. package/dist/backend/services/asset-references.d.ts +4 -0
  172. package/dist/backend/services/asset-references.d.ts.map +1 -0
  173. package/dist/backend/services/asset-references.js +55 -0
  174. package/dist/backend/services/asset-references.js.map +1 -0
  175. package/dist/backend/services/cms-block-read-port.d.ts +27 -0
  176. package/dist/backend/services/cms-block-read-port.d.ts.map +1 -0
  177. package/dist/backend/services/cms-block-read-port.js +50 -0
  178. package/dist/backend/services/cms-block-read-port.js.map +1 -0
  179. package/dist/backend/services/cms-block-seed-port.d.ts +31 -0
  180. package/dist/backend/services/cms-block-seed-port.d.ts.map +1 -0
  181. package/dist/backend/services/cms-block-seed-port.js +68 -0
  182. package/dist/backend/services/cms-block-seed-port.js.map +1 -0
  183. package/dist/backend/services/cms-block-service.d.ts +38 -0
  184. package/dist/backend/services/cms-block-service.d.ts.map +1 -0
  185. package/dist/backend/services/cms-block-service.js +218 -0
  186. package/dist/backend/services/cms-block-service.js.map +1 -0
  187. package/dist/backend/services/cms-cache.d.ts +54 -0
  188. package/dist/backend/services/cms-cache.d.ts.map +1 -0
  189. package/dist/backend/services/cms-cache.js +113 -0
  190. package/dist/backend/services/cms-cache.js.map +1 -0
  191. package/dist/backend/services/cms-hook-service.d.ts +35 -0
  192. package/dist/backend/services/cms-hook-service.d.ts.map +1 -0
  193. package/dist/backend/services/cms-hook-service.js +216 -0
  194. package/dist/backend/services/cms-hook-service.js.map +1 -0
  195. package/dist/backend/services/cms-language-reference.d.ts +11 -0
  196. package/dist/backend/services/cms-language-reference.d.ts.map +1 -0
  197. package/dist/backend/services/cms-language-reference.js +26 -0
  198. package/dist/backend/services/cms-language-reference.js.map +1 -0
  199. package/dist/backend/services/cms-page-read-port.d.ts +23 -0
  200. package/dist/backend/services/cms-page-read-port.d.ts.map +1 -0
  201. package/dist/backend/services/cms-page-read-port.js +54 -0
  202. package/dist/backend/services/cms-page-read-port.js.map +1 -0
  203. package/dist/backend/services/cms-page-service.d.ts +104 -0
  204. package/dist/backend/services/cms-page-service.d.ts.map +1 -0
  205. package/dist/backend/services/cms-page-service.js +468 -0
  206. package/dist/backend/services/cms-page-service.js.map +1 -0
  207. package/dist/backend/services/cms-reference-registry.d.ts +30 -0
  208. package/dist/backend/services/cms-reference-registry.d.ts.map +1 -0
  209. package/dist/backend/services/cms-reference-registry.js +98 -0
  210. package/dist/backend/services/cms-reference-registry.js.map +1 -0
  211. package/dist/backend/services/cms-template-service.d.ts +37 -0
  212. package/dist/backend/services/cms-template-service.d.ts.map +1 -0
  213. package/dist/backend/services/cms-template-service.js +205 -0
  214. package/dist/backend/services/cms-template-service.js.map +1 -0
  215. package/dist/backend/services/content-tree-walker.d.ts +7 -0
  216. package/dist/backend/services/content-tree-walker.d.ts.map +1 -0
  217. package/dist/backend/services/content-tree-walker.js +89 -0
  218. package/dist/backend/services/content-tree-walker.js.map +1 -0
  219. package/dist/backend/services/page-builder-registry.d.ts +120 -0
  220. package/dist/backend/services/page-builder-registry.d.ts.map +1 -0
  221. package/dist/backend/services/page-builder-registry.js +220 -0
  222. package/dist/backend/services/page-builder-registry.js.map +1 -0
  223. package/dist/backend/services/seed-hooks.d.ts +22 -0
  224. package/dist/backend/services/seed-hooks.d.ts.map +1 -0
  225. package/dist/backend/services/seed-hooks.js +94 -0
  226. package/dist/backend/services/seed-hooks.js.map +1 -0
  227. package/dist/backend/services/storefront-resolver.d.ts +71 -0
  228. package/dist/backend/services/storefront-resolver.d.ts.map +1 -0
  229. package/dist/backend/services/storefront-resolver.js +329 -0
  230. package/dist/backend/services/storefront-resolver.js.map +1 -0
  231. package/dist/manifest.d.ts +225 -0
  232. package/dist/manifest.d.ts.map +1 -0
  233. package/dist/manifest.js +695 -0
  234. package/dist/manifest.js.map +1 -0
  235. package/dist/migrations/20260425T162418_cms_pages_init.d.ts +10 -0
  236. package/dist/migrations/20260425T162418_cms_pages_init.d.ts.map +1 -0
  237. package/dist/migrations/20260425T162418_cms_pages_init.js +30 -0
  238. package/dist/migrations/20260425T162418_cms_pages_init.js.map +1 -0
  239. package/dist/migrations/20260505T130214_cms_init.d.ts +28 -0
  240. package/dist/migrations/20260505T130214_cms_init.d.ts.map +1 -0
  241. package/dist/migrations/20260505T130214_cms_init.js +332 -0
  242. package/dist/migrations/20260505T130214_cms_init.js.map +1 -0
  243. package/dist/migrations/20260903T101741_cms_namespace_block_names.d.ts +6 -0
  244. package/dist/migrations/20260903T101741_cms_namespace_block_names.d.ts.map +1 -0
  245. package/dist/migrations/20260903T101741_cms_namespace_block_names.js +60 -0
  246. package/dist/migrations/20260903T101741_cms_namespace_block_names.js.map +1 -0
  247. package/dist/migrations/20260912T094733_cms_sales_channel_cms_pages.d.ts +27 -0
  248. package/dist/migrations/20260912T094733_cms_sales_channel_cms_pages.d.ts.map +1 -0
  249. package/dist/migrations/20260912T094733_cms_sales_channel_cms_pages.js +44 -0
  250. package/dist/migrations/20260912T094733_cms_sales_channel_cms_pages.js.map +1 -0
  251. package/dist/migrations/20260912T125709_cms_page_body_asset_ref_index.d.ts +32 -0
  252. package/dist/migrations/20260912T125709_cms_page_body_asset_ref_index.d.ts.map +1 -0
  253. package/dist/migrations/20260912T125709_cms_page_body_asset_ref_index.js +36 -0
  254. package/dist/migrations/20260912T125709_cms_page_body_asset_ref_index.js.map +1 -0
  255. package/dist/migrations/index.d.ts +31 -0
  256. package/dist/migrations/index.d.ts.map +1 -0
  257. package/dist/migrations/index.js +37 -0
  258. package/dist/migrations/index.js.map +1 -0
  259. package/docs/cms/extending-page-builder.md +256 -0
  260. package/docs/cms/index.md +233 -0
  261. package/i18n/en.json +231 -0
  262. package/i18n/pl.json +231 -0
  263. package/package.json +125 -3
  264. package/tailwind.css +16 -0
@@ -0,0 +1,695 @@
1
+ import { defineModuleManifest, defineModuleSettingsManifest, } from '@endora-commerce/contracts';
2
+ import { DEFAULT_BREAKPOINTS } from '@endora-commerce/page-builder-core/types/responsive';
3
+ export const CMS_PAGE_BUILDER_SETTING_CODES = {
4
+ BREAKPOINT_TABLET_MIN: 'cms.page_builder.breakpoint.tablet_min',
5
+ BREAKPOINT_DESKTOP_MIN: 'cms.page_builder.breakpoint.desktop_min',
6
+ COLOR_PALETTE: 'cms.page_builder.color_palette',
7
+ };
8
+ /**
9
+ * The deployment's reserved first path segments
10
+ * (`specs/105-cms-root-page-urls/` FR-031/FR-032;
11
+ * `contracts/cms-page-url.md` §5.2).
12
+ *
13
+ * A CMS page lives at the storefront root, `/{slug}`, so a page slugged
14
+ * `cart` saves, publishes and is never served: a root catch-all is Next's
15
+ * lowest-priority match and the storefront's own `/cart` wins. Nothing here
16
+ * creates that precedence and nothing may (§5.0) — this value is what lets the
17
+ * module tell the operator *before* the page disappears.
18
+ *
19
+ * **The value is the deployment's and the default is empty**, which is not a
20
+ * gap left open. The set is a fact about a *storefront's route table*; a
21
+ * headless backend serves storefronts it did not build, so a list shipped in
22
+ * `cms` would be a derived fact about a consumer written into the owner — stale
23
+ * the first time any client adds a route, and stale in the direction that fails
24
+ * open. The reference storefront publishes its own segments as
25
+ * `RESERVED_TOP_LEVEL_SEGMENTS` (`storefront/app/reserved-segments.ts`),
26
+ * reconciled against its route tree by `check:storefront-indexability`, and a
27
+ * deployment copies its value from there.
28
+ */
29
+ export const CMS_SETTING_CODES = {
30
+ RESERVED_SLUG_SEGMENTS: 'cms.reserved_slug_segments',
31
+ };
32
+ const settings = defineModuleSettingsManifest({
33
+ moduleCode: 'cms',
34
+ groups: [
35
+ { code: 'cms', name: 'CMS' },
36
+ { code: 'cms_page_builder', name: 'Page Builder' },
37
+ ],
38
+ settings: [
39
+ {
40
+ // Feature 073 — the operator's activation control. Platform-wide.
41
+ code: 'cms.enabled',
42
+ name: 'CMS enabled',
43
+ description: 'Switches the CMS admin screens, its API and the storefront pages, blocks and hooks it serves on or off. Nothing is dropped: pages, blocks, templates and hook attachments stay in the database and reappear exactly as they were when you switch it back on.',
44
+ groupCode: 'cms',
45
+ valueType: 'boolean',
46
+ defaultValue: true,
47
+ },
48
+ {
49
+ // Feature 105 — the deployment's reserved first path segments. See
50
+ // `CMS_SETTING_CODES` above for why the list is yours and not ours.
51
+ code: CMS_SETTING_CODES.RESERVED_SLUG_SEGMENTS,
52
+ name: 'Reserved page-slug segments',
53
+ description: 'First path segments your storefront already serves, as a JSON array of strings — for example ["cart","checkout","catalog"]. A CMS page is served at your storefront root, so a page whose slug starts with one of these would never be shown: the storefront route wins. Saving such a page is refused, and the page editor warns while the slug is being typed. Leave it empty and nothing is refused. The reference storefront publishes the segments it owns in storefront/app/reserved-segments.ts; a custom storefront has its own list.',
54
+ groupCode: 'cms',
55
+ valueType: 'json',
56
+ defaultValue: [],
57
+ },
58
+ {
59
+ code: CMS_PAGE_BUILDER_SETTING_CODES.BREAKPOINT_TABLET_MIN,
60
+ name: 'Tablet breakpoint (min-width px)',
61
+ description: 'Minimum viewport width in pixels for the tablet tier in the CMS Page Builder preview and responsive styles.',
62
+ groupCode: 'cms_page_builder',
63
+ valueType: 'number',
64
+ defaultValue: DEFAULT_BREAKPOINTS.tabletMin,
65
+ },
66
+ {
67
+ code: CMS_PAGE_BUILDER_SETTING_CODES.BREAKPOINT_DESKTOP_MIN,
68
+ name: 'Desktop breakpoint (min-width px)',
69
+ description: 'Minimum viewport width in pixels for the desktop tier in the CMS Page Builder preview and responsive styles.',
70
+ groupCode: 'cms_page_builder',
71
+ valueType: 'number',
72
+ defaultValue: DEFAULT_BREAKPOINTS.desktopMin,
73
+ },
74
+ {
75
+ code: CMS_PAGE_BUILDER_SETTING_CODES.COLOR_PALETTE,
76
+ name: 'Page Builder color palette',
77
+ description: 'Global named colors available in the CMS Page Builder color fields. Each entry has a display name and hex value.',
78
+ groupCode: 'cms_page_builder',
79
+ valueType: 'json',
80
+ defaultValue: [],
81
+ },
82
+ ],
83
+ });
84
+ export const cmsSettingsManifest = settings;
85
+ export const manifest = defineModuleManifest({
86
+ id: 'cms',
87
+ name: 'CMS',
88
+ description: 'Pages, blocks, templates, and hooks for content management.',
89
+ version: '1.0.0',
90
+ /**
91
+ * What this module needs from the environment (`specs/117-instance-bring-up/`
92
+ * FR-002). Only what it **owns**: its reads of platform-owned names are
93
+ * satisfied by `packages/platform/src/env/index.ts`.
94
+ *
95
+ * Why each of these is not a Setting is its entry in
96
+ * `backend/scripts/ledgers/module-environment-inputs/cms.ts`.
97
+ */
98
+ env: [
99
+ {
100
+ name: 'CMS_PB_BREAKPOINT_TABLET_MIN',
101
+ describes: {
102
+ en: 'The viewport width, in pixels, at which the Page Builder’s tablet preview begins.',
103
+ pl: 'Szerokość okna w pikselach, od której zaczyna się podgląd tabletowy w kreatorze stron.',
104
+ },
105
+ requirement: {
106
+ kind: 'optional',
107
+ without: {
108
+ en: 'The Page Builder previews at the platform’s breakpoints rather than this storefront theme’s, so an editor lays pages out against widths the shop does not use.',
109
+ pl: 'Kreator stron pokazuje podgląd przy punktach granicznych platformy, a nie motywu tego sklepu, więc redaktor układa strony dla szerokości, których sklep nie używa.',
110
+ },
111
+ },
112
+ secret: false,
113
+ generable: false,
114
+ owner: { kind: 'module', moduleId: 'cms' },
115
+ consumers: ['backend'],
116
+ addressOf: null,
117
+ },
118
+ {
119
+ name: 'CMS_PB_BREAKPOINT_DESKTOP_MIN',
120
+ describes: {
121
+ en: 'The viewport width, in pixels, at which the Page Builder’s desktop preview begins.',
122
+ pl: 'Szerokość okna w pikselach, od której zaczyna się podgląd desktopowy w kreatorze stron.',
123
+ },
124
+ requirement: {
125
+ kind: 'optional',
126
+ without: {
127
+ en: 'The Page Builder previews at the platform’s breakpoints rather than this storefront theme’s, so an editor lays pages out against widths the shop does not use.',
128
+ pl: 'Kreator stron pokazuje podgląd przy punktach granicznych platformy, a nie motywu tego sklepu, więc redaktor układa strony dla szerokości, których sklep nie używa.',
129
+ },
130
+ },
131
+ secret: false,
132
+ generable: false,
133
+ owner: { kind: 'module', moduleId: 'cms' },
134
+ consumers: ['backend'],
135
+ addressOf: null,
136
+ },
137
+ ],
138
+ // `auth` owns the `requireAdmin` port both route files are gated by, and
139
+ // `settings` owns the store the page-builder resolvers read and write.
140
+ // `assets_library` owns the reference registry this module contributes its
141
+ // embedded-asset scan to (T143a) — the edge existed as a composition root's
142
+ // cross-registration, which is to say it existed nowhere an operator, the
143
+ // lifecycle or the migration order could see it.
144
+ // `languages` owns `languageReferenceRegistry`, the registry this module
145
+ // contributes its "which languages do pages carry" descriptor to (feature 077,
146
+ // D-87). `languages` used to ask the question itself, with a jsonb
147
+ // containment test against `cms_pages` — this module's table.
148
+ dependencies: ['assets_library', 'languages', 'sales_channels', 'auth', 'settings'],
149
+ /**
150
+ * Error codes this module owns — feature 090, Phase 3
151
+ * (`specs/090-module-owned-error-codes/`).
152
+ *
153
+ * The list is the incumbent prefix chain's **answer**, copied from the frozen
154
+ * capture (`backend/test/fixtures/error-code-routing/chain-answers.ts`, taken
155
+ * at `49f3c6817`) rather than judged: the migration is answer-preserving over
156
+ * all 289 codes and re-routing is out of scope (runbook §6.5). Ten codes, and
157
+ * this module happens to be the clean case for trap T1 — the chain's
158
+ * `startsWith('CMS_')` rule shadows nothing and is shadowed by nothing, so its
159
+ * source and its answer agree here, which is not true of the four codes T1
160
+ * names.
161
+ *
162
+ * **Two names a reader would attribute elsewhere, and both are ours.**
163
+ * `CMS_LANGUAGE_NOT_IN_CHANNEL_SCOPE` names two other modules' nouns and
164
+ * belongs to neither: it is raised twice in `cms-page-service.ts`, once when a
165
+ * page's content is written in a language the page does not carry and once
166
+ * when a page's declared languages are not in the union its assigned sales
167
+ * channels resolve. `megamenu` owns the identically shaped
168
+ * `MEGAMENU_LANGUAGE_NOT_IN_CHANNEL_SCOPE` on the same reading.
169
+ * `CMS_REFERENCED` is the cross-entity reference guard for pages, blocks and
170
+ * templates — not a narrowing of `assets_library`'s `ASSET_REFERENCED`, which
171
+ * is that module's and stays there.
172
+ *
173
+ * **And the inverse: seven raises this module makes and must not declare.**
174
+ * `VERSION_CONFLICT` four times (the `If-Match` guard in each of the four
175
+ * entity services) and `VALIDATION_FAILED` three times (the storefront
176
+ * route's missing-parameter refusals). Both route to `core`, because
177
+ * ownership follows the domain noun and never the thrower (D-95.2).
178
+ *
179
+ * **No `tokens`, and that is derived rather than assumed.** The envelope's
180
+ * `refusalToken` (`packages/platform/src/http/error-envelope.ts`) reads one
181
+ * member of `details` — `code` — as the tail of `errors.<CODE>.<token>`. All
182
+ * 32 raises of these ten codes were enumerated over `packages` and
183
+ * `backend/src` in both spellings (`ERROR_CODES.<CODE>` and the bare string
184
+ * literal, runbook step 2), and not one passes a fourth argument at all;
185
+ * neither do the seven `core`-owned raises above. The runbook §5 tree-wide
186
+ * scan agrees, printing the same ten codes over 41 sites it has printed since
187
+ * `catalog`, none of them a `CMS_` one. The bundle agrees from the other
188
+ * direction: ten `errors.<CODE>` keys in `en` and `pl`, no
189
+ * `errors.<CODE>.<token>` key in either.
190
+ *
191
+ * **One code nothing raises: `CMS_SCHEMA_UPGRADE_FAILED`** — declared anyway,
192
+ * because ownership follows the capture (trap T10) and deleting it would move
193
+ * an answer this merge request may not move. It is reported, not repaired;
194
+ * the finding is in the merge request and belongs to
195
+ * `specs/deferred-defects.md` § *Roughly 29 error codes have translated
196
+ * sentences no client can ever receive*.
197
+ */
198
+ errorCodes: [
199
+ { code: 'CMS_BLOCK_NOT_FOUND' },
200
+ { code: 'CMS_CODE_CONFLICT' },
201
+ { code: 'CMS_HOOK_NOT_FOUND' },
202
+ { code: 'CMS_HOOK_SYSTEM_PROTECTED' },
203
+ { code: 'CMS_LANGUAGE_NOT_IN_CHANNEL_SCOPE' },
204
+ { code: 'CMS_PAGE_NOT_FOUND' },
205
+ { code: 'CMS_REFERENCED' },
206
+ { code: 'CMS_SCHEMA_UPGRADE_FAILED' },
207
+ { code: 'CMS_SLUG_CONFLICT' },
208
+ // Feature 105. Its sentence names the offending segment through the
209
+ // envelope's `details` → `{placeholder}` path, so the operator reads which
210
+ // path would win rather than being told a slug is "invalid".
211
+ { code: 'CMS_SLUG_RESERVED' },
212
+ { code: 'CMS_TEMPLATE_NOT_FOUND' },
213
+ ],
214
+ i18n: { bundlesDir: 'i18n' },
215
+ docs: { dir: 'docs' },
216
+ settings,
217
+ permissions: [
218
+ { code: 'cms.read', label: 'View CMS content' },
219
+ { code: 'cms.write', label: 'Edit CMS content' },
220
+ ],
221
+ actions: [
222
+ {
223
+ id: 'new-page',
224
+ labelKey: 'actions.newPage.label',
225
+ descriptionKey: 'actions.newPage.description',
226
+ icon: 'FileText',
227
+ targetRoute: '/cms/pages/new',
228
+ requiredPermission: 'cms.write',
229
+ keywords: ['page', 'new', 'create', 'strona', 'nowa', 'utwórz'],
230
+ weight: 130,
231
+ },
232
+ ],
233
+ // Feature 073 — the operator's activation control. A platform without a CMS
234
+ // is a smaller platform, not a broken one: pages, blocks and hooks are
235
+ // content, and switching the module off hides the screens and the storefront
236
+ // surface without dropping a row.
237
+ activation: { settingCode: 'cms.enabled', default: true },
238
+ /**
239
+ * The 30 Page Builder blocks this module owns, and the eight CMS palette
240
+ * sections its own blocks populate (feature 096,
241
+ * `specs/096-page-builder-block-ownership/` §7.1 and §2.1).
242
+ *
243
+ * `catalog` is **not** among them although the CMS palette renders a Catalog
244
+ * section today: `cms` owns no block in it, the five that populate it are
245
+ * `catalog`'s, and a section is declared by the module whose blocks occupy it
246
+ * (`contracts/block-definition.md` §1.1's authoring guidance).
247
+ *
248
+ * `internal` is the hidden drawer that keeps `cms.Column` and `cms.Slide` out
249
+ * of Puck's *Other* group, where they are insertable outside their parent and
250
+ * render wrong. It was keyed `_internal` until this feature; the key grammar
251
+ * `blockCategoryKeyRe` forbids a leading underscore, so it is `internal` —
252
+ * the same word, the same title and the same behaviour.
253
+ *
254
+ * `fields` and `previewIcon` are the registration at `plugin.ts`'s
255
+ * `register('cms', …)` call, moved rather than rewritten; `responsiveFields`
256
+ * are `defaultPageBuilderConfig`'s. Nothing reads either through the manifest
257
+ * until Phase 2's registry work (T209/T210).
258
+ */
259
+ blocks: [
260
+ {
261
+ name: 'cms.Row',
262
+ labelKey: 'blocks.row.label',
263
+ descriptionKey: 'blocks.row.description',
264
+ category: 'layout',
265
+ contexts: ['cms'],
266
+ fields: {
267
+ gap: { type: 'number', label: 'Gap' },
268
+ align: {
269
+ type: 'select',
270
+ label: 'Align',
271
+ options: [
272
+ { label: 'stretch', value: 'stretch' },
273
+ { label: 'start', value: 'start' },
274
+ { label: 'center', value: 'center' },
275
+ { label: 'end', value: 'end' },
276
+ ],
277
+ },
278
+ },
279
+ responsiveFields: [
280
+ 'contentMaxWidth',
281
+ 'customMaxWidthPx',
282
+ 'contentPosition',
283
+ 'minHeight',
284
+ 'gap',
285
+ 'rowGap',
286
+ 'verticalAlign',
287
+ 'margin',
288
+ 'padding',
289
+ 'border',
290
+ ],
291
+ weight: 10,
292
+ },
293
+ {
294
+ name: 'cms.Spacer',
295
+ labelKey: 'blocks.spacer.label',
296
+ descriptionKey: 'blocks.spacer.description',
297
+ category: 'layout',
298
+ contexts: ['cms'],
299
+ fields: { heightPx: { type: 'number', label: 'Height' } },
300
+ responsiveFields: ['heightPx'],
301
+ weight: 20,
302
+ },
303
+ {
304
+ name: 'cms.Heading',
305
+ labelKey: 'blocks.heading.label',
306
+ descriptionKey: 'blocks.heading.description',
307
+ category: 'content',
308
+ contexts: ['cms'],
309
+ fields: {
310
+ level: {
311
+ type: 'select',
312
+ label: 'Level',
313
+ options: [
314
+ { label: 'H1', value: 1 },
315
+ { label: 'H2', value: 2 },
316
+ { label: 'H3', value: 3 },
317
+ { label: 'H4', value: 4 },
318
+ { label: 'H5', value: 5 },
319
+ { label: 'H6', value: 6 },
320
+ ],
321
+ },
322
+ text: { type: 'text', label: 'Text' },
323
+ },
324
+ responsiveFields: [
325
+ 'fontSize',
326
+ 'fontWeight',
327
+ 'textAlign',
328
+ 'lineHeight',
329
+ 'margin',
330
+ 'padding',
331
+ 'border',
332
+ ],
333
+ weight: 10,
334
+ },
335
+ {
336
+ name: 'cms.Text',
337
+ labelKey: 'blocks.text.label',
338
+ descriptionKey: 'blocks.text.description',
339
+ category: 'content',
340
+ contexts: ['cms'],
341
+ fields: { text: { type: 'text', label: 'Text' } },
342
+ responsiveFields: [
343
+ 'fontSize',
344
+ 'fontWeight',
345
+ 'textAlign',
346
+ 'lineHeight',
347
+ 'margin',
348
+ 'padding',
349
+ 'border',
350
+ ],
351
+ weight: 20,
352
+ },
353
+ {
354
+ name: 'cms.RichContent',
355
+ labelKey: 'blocks.richContent.label',
356
+ descriptionKey: 'blocks.richContent.description',
357
+ category: 'content',
358
+ contexts: ['cms'],
359
+ fields: { content: { type: 'richtext', label: 'Content' } },
360
+ responsiveFields: ['margin', 'padding', 'border'],
361
+ weight: 30,
362
+ },
363
+ {
364
+ name: 'cms.Button',
365
+ labelKey: 'blocks.button.label',
366
+ descriptionKey: 'blocks.button.description',
367
+ category: 'content',
368
+ contexts: ['cms'],
369
+ fields: {
370
+ label: { type: 'text', label: 'Label', required: true },
371
+ href: { type: 'text', label: 'Link target', required: true },
372
+ variant: {
373
+ type: 'select',
374
+ label: 'Variant',
375
+ options: [
376
+ { label: 'primary', value: 'primary' },
377
+ { label: 'secondary', value: 'secondary' },
378
+ { label: 'ghost', value: 'ghost' },
379
+ ],
380
+ },
381
+ },
382
+ responsiveFields: ['variant', 'margin', 'padding', 'border'],
383
+ weight: 40,
384
+ },
385
+ {
386
+ name: 'cms.Image',
387
+ labelKey: 'blocks.image.label',
388
+ descriptionKey: 'blocks.image.description',
389
+ category: 'content',
390
+ contexts: ['cms'],
391
+ fields: {
392
+ src: { type: 'text', label: 'Image URL', required: true },
393
+ alt: { type: 'text', label: 'Alt text' },
394
+ },
395
+ responsiveFields: ['widthMode', 'widthPx', 'align', 'margin', 'padding', 'border'],
396
+ weight: 50,
397
+ },
398
+ {
399
+ name: 'cms.Icons',
400
+ labelKey: 'blocks.icons.label',
401
+ descriptionKey: 'blocks.icons.description',
402
+ category: 'content',
403
+ contexts: ['cms'],
404
+ fields: {
405
+ name: { type: 'text', label: 'Icon name' },
406
+ size: { type: 'number', label: 'Size' },
407
+ },
408
+ responsiveFields: ['align', 'margin', 'padding', 'border'],
409
+ previewIcon: 'sparkles',
410
+ weight: 60,
411
+ },
412
+ {
413
+ name: 'cms.Social',
414
+ labelKey: 'blocks.social.label',
415
+ descriptionKey: 'blocks.social.description',
416
+ category: 'content',
417
+ contexts: ['cms'],
418
+ fields: {
419
+ layout: {
420
+ type: 'select',
421
+ label: 'Layout',
422
+ options: [
423
+ { label: 'Icons only', value: 'icons-only' },
424
+ { label: 'Icons with labels', value: 'icons-with-labels' },
425
+ { label: 'Vertical list', value: 'vertical-list' },
426
+ { label: 'Pills', value: 'pills' },
427
+ ],
428
+ },
429
+ },
430
+ responsiveFields: ['align', 'margin', 'padding', 'border'],
431
+ previewIcon: 'share',
432
+ weight: 70,
433
+ },
434
+ {
435
+ name: 'cms.FeatureList',
436
+ labelKey: 'blocks.featureList.label',
437
+ descriptionKey: 'blocks.featureList.description',
438
+ category: 'content',
439
+ contexts: ['cms'],
440
+ fields: {},
441
+ responsiveFields: ['columns', 'gap', 'margin', 'padding', 'border'],
442
+ previewIcon: 'layout',
443
+ weight: 80,
444
+ },
445
+ {
446
+ name: 'cms.Hero',
447
+ labelKey: 'blocks.hero.label',
448
+ descriptionKey: 'blocks.hero.description',
449
+ category: 'content',
450
+ contexts: ['cms'],
451
+ fields: { heading: { type: 'text', label: 'Heading' } },
452
+ responsiveFields: ['minHeightPx', 'margin', 'padding', 'border'],
453
+ weight: 90,
454
+ },
455
+ {
456
+ name: 'cms.LogoStrip',
457
+ labelKey: 'blocks.logoStrip.label',
458
+ descriptionKey: 'blocks.logoStrip.description',
459
+ category: 'content',
460
+ contexts: ['cms'],
461
+ fields: {},
462
+ responsiveFields: ['margin', 'padding', 'border'],
463
+ weight: 100,
464
+ },
465
+ {
466
+ name: 'cms.Testimonial',
467
+ labelKey: 'blocks.testimonial.label',
468
+ descriptionKey: 'blocks.testimonial.description',
469
+ category: 'content',
470
+ contexts: ['cms'],
471
+ fields: { quote: { type: 'textarea', label: 'Quote' } },
472
+ responsiveFields: ['margin', 'padding', 'border'],
473
+ weight: 110,
474
+ },
475
+ {
476
+ name: 'cms.Stats',
477
+ labelKey: 'blocks.stats.label',
478
+ descriptionKey: 'blocks.stats.description',
479
+ category: 'content',
480
+ contexts: ['cms'],
481
+ fields: {},
482
+ responsiveFields: ['columns', 'margin', 'padding', 'border'],
483
+ weight: 120,
484
+ },
485
+ {
486
+ name: 'cms.AnnouncementBar',
487
+ labelKey: 'blocks.announcementBar.label',
488
+ descriptionKey: 'blocks.announcementBar.description',
489
+ category: 'content',
490
+ contexts: ['cms'],
491
+ fields: { text: { type: 'text', label: 'Message' } },
492
+ weight: 130,
493
+ },
494
+ {
495
+ name: 'cms.SimpleTable',
496
+ labelKey: 'blocks.simpleTable.label',
497
+ descriptionKey: 'blocks.simpleTable.description',
498
+ category: 'content',
499
+ contexts: ['cms'],
500
+ fields: {},
501
+ responsiveFields: ['margin', 'padding', 'border'],
502
+ weight: 140,
503
+ },
504
+ {
505
+ name: 'cms.Video',
506
+ labelKey: 'blocks.video.label',
507
+ descriptionKey: 'blocks.video.description',
508
+ category: 'media',
509
+ contexts: ['cms'],
510
+ fields: { url: { type: 'text', label: 'Video URL' } },
511
+ responsiveFields: ['maxWidth', 'align', 'margin', 'padding', 'border'],
512
+ weight: 10,
513
+ },
514
+ {
515
+ name: 'cms.Map',
516
+ labelKey: 'blocks.map.label',
517
+ descriptionKey: 'blocks.map.description',
518
+ category: 'media',
519
+ contexts: ['cms'],
520
+ fields: {
521
+ provider: {
522
+ type: 'select',
523
+ label: 'Provider',
524
+ options: [
525
+ { label: 'Leaflet + OSM', value: 'leaflet' },
526
+ { label: 'Google Maps', value: 'google' },
527
+ ],
528
+ },
529
+ },
530
+ responsiveFields: ['height', 'margin', 'padding', 'border'],
531
+ weight: 20,
532
+ },
533
+ {
534
+ name: 'cms.ContentSlider',
535
+ labelKey: 'blocks.contentSlider.label',
536
+ descriptionKey: 'blocks.contentSlider.description',
537
+ category: 'interactive',
538
+ contexts: ['cms'],
539
+ fields: {},
540
+ responsiveFields: ['slidesPerView', 'gap', 'margin', 'padding', 'border'],
541
+ weight: 10,
542
+ },
543
+ {
544
+ name: 'cms.ImageSlider',
545
+ labelKey: 'blocks.imageSlider.label',
546
+ descriptionKey: 'blocks.imageSlider.description',
547
+ category: 'interactive',
548
+ contexts: ['cms'],
549
+ fields: {},
550
+ responsiveFields: ['slidesPerView', 'gap', 'margin', 'padding', 'border'],
551
+ weight: 20,
552
+ },
553
+ {
554
+ name: 'cms.Tabs',
555
+ labelKey: 'blocks.tabs.label',
556
+ descriptionKey: 'blocks.tabs.description',
557
+ category: 'interactive',
558
+ contexts: ['cms'],
559
+ fields: {},
560
+ responsiveFields: ['margin', 'padding', 'border'],
561
+ weight: 30,
562
+ },
563
+ {
564
+ name: 'cms.Accordion',
565
+ labelKey: 'blocks.accordion.label',
566
+ descriptionKey: 'blocks.accordion.description',
567
+ category: 'interactive',
568
+ contexts: ['cms'],
569
+ fields: {},
570
+ responsiveFields: ['margin', 'padding', 'border'],
571
+ weight: 40,
572
+ },
573
+ {
574
+ name: 'cms.Column',
575
+ labelKey: 'blocks.column.label',
576
+ descriptionKey: 'blocks.column.description',
577
+ category: 'internal',
578
+ contexts: ['cms'],
579
+ fields: { span: { type: 'number', label: 'Width (1–12)' } },
580
+ responsiveFields: ['span', 'margin', 'padding', 'border'],
581
+ weight: 10,
582
+ },
583
+ {
584
+ name: 'cms.Slide',
585
+ labelKey: 'blocks.slide.label',
586
+ descriptionKey: 'blocks.slide.description',
587
+ category: 'internal',
588
+ contexts: ['cms'],
589
+ fields: {},
590
+ responsiveFields: ['margin', 'padding', 'border'],
591
+ weight: 20,
592
+ },
593
+ {
594
+ name: 'cms.NewsletterSignup',
595
+ labelKey: 'blocks.newsletterSignup.label',
596
+ descriptionKey: 'blocks.newsletterSignup.description',
597
+ category: 'forms',
598
+ contexts: ['cms'],
599
+ fields: {},
600
+ responsiveFields: ['margin', 'padding', 'border'],
601
+ weight: 10,
602
+ },
603
+ {
604
+ name: 'cms.ContactFormEmbed',
605
+ labelKey: 'blocks.contactFormEmbed.label',
606
+ descriptionKey: 'blocks.contactFormEmbed.description',
607
+ category: 'forms',
608
+ contexts: ['cms'],
609
+ fields: {},
610
+ responsiveFields: ['margin', 'padding', 'border'],
611
+ weight: 20,
612
+ },
613
+ {
614
+ name: 'cms.RawHtml',
615
+ labelKey: 'blocks.rawHtml.label',
616
+ descriptionKey: 'blocks.rawHtml.description',
617
+ category: 'advanced',
618
+ contexts: ['cms'],
619
+ fields: { html: { type: 'textarea', label: 'HTML' } },
620
+ responsiveFields: ['margin', 'padding', 'border'],
621
+ weight: 10,
622
+ },
623
+ {
624
+ name: 'cms.RawJs',
625
+ labelKey: 'blocks.rawJs.label',
626
+ descriptionKey: 'blocks.rawJs.description',
627
+ category: 'advanced',
628
+ contexts: ['cms'],
629
+ fields: { script: { type: 'textarea', label: 'JavaScript' } },
630
+ responsiveFields: ['margin', 'padding', 'border'],
631
+ weight: 20,
632
+ },
633
+ {
634
+ name: 'cms.InsertBlock',
635
+ labelKey: 'blocks.insertBlock.label',
636
+ descriptionKey: 'blocks.insertBlock.description',
637
+ category: 'embeds',
638
+ contexts: ['cms'],
639
+ fields: { code: { type: 'text', label: 'Block code', required: true } },
640
+ weight: 10,
641
+ },
642
+ {
643
+ name: 'cms.InsertTemplate',
644
+ labelKey: 'blocks.insertTemplate.label',
645
+ descriptionKey: 'blocks.insertTemplate.description',
646
+ category: 'embeds',
647
+ contexts: ['cms'],
648
+ fields: { code: { type: 'text', label: 'Template code', required: true } },
649
+ weight: 20,
650
+ },
651
+ ],
652
+ blockCategories: [
653
+ { key: 'layout', titleKey: 'blocks.category.layout', contexts: ['cms'], weight: 10 },
654
+ { key: 'content', titleKey: 'blocks.category.content', contexts: ['cms'], weight: 20 },
655
+ { key: 'media', titleKey: 'blocks.category.media', contexts: ['cms'], weight: 30 },
656
+ { key: 'interactive', titleKey: 'blocks.category.interactive', contexts: ['cms'], weight: 50 },
657
+ {
658
+ key: 'internal',
659
+ titleKey: 'blocks.category.internal',
660
+ contexts: ['cms'],
661
+ weight: 60,
662
+ visible: false,
663
+ },
664
+ { key: 'forms', titleKey: 'blocks.category.forms', contexts: ['cms'], weight: 70 },
665
+ { key: 'advanced', titleKey: 'blocks.category.advanced', contexts: ['cms'], weight: 80 },
666
+ { key: 'embeds', titleKey: 'blocks.category.embeds', contexts: ['cms'], weight: 90 },
667
+ ],
668
+ });
669
+ export function resolvePageBuilderBreakpointsFromEnv() {
670
+ const tabletRaw = process.env['CMS_PB_BREAKPOINT_TABLET_MIN'];
671
+ const desktopRaw = process.env['CMS_PB_BREAKPOINT_DESKTOP_MIN'];
672
+ const tabletMin = tabletRaw ? Number.parseInt(tabletRaw, 10) : DEFAULT_BREAKPOINTS.tabletMin;
673
+ const desktopMin = desktopRaw ? Number.parseInt(desktopRaw, 10) : DEFAULT_BREAKPOINTS.desktopMin;
674
+ return {
675
+ tabletMin: Number.isFinite(tabletMin) ? tabletMin : DEFAULT_BREAKPOINTS.tabletMin,
676
+ desktopMin: Number.isFinite(desktopMin) ? desktopMin : DEFAULT_BREAKPOINTS.desktopMin,
677
+ };
678
+ }
679
+ /**
680
+ * The operator's pre-flight report for the block-name migration (feature 096,
681
+ * T410; `contracts/block-name-migration.md` §7).
682
+ *
683
+ * The body is `await import()`ed so the generated manifest index stays light —
684
+ * this file is loaded by every check and every composition, and the report pulls
685
+ * in the frozen rename map and the structural walk.
686
+ */
687
+ export const cliCommands = [
688
+ {
689
+ name: 'block-names',
690
+ summary: 'Report the Page Builder block names stored in this database, and what the ' +
691
+ 'namespacing migration will do to each. Read-only.',
692
+ run: async (context) => (await import('./backend/cli/block-names.js')).blockNames(context),
693
+ },
694
+ ];
695
+ //# sourceMappingURL=manifest.js.map