@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,220 @@
1
+ // Page Builder component registry — feature 014 / T028, rebuilt on module
2
+ // declarations by feature 096 (T209/T210).
3
+ //
4
+ // **It is populated from the composed modules' manifests, not from a call.**
5
+ // Until 2026-09-03 it was populated by a single hand-written
6
+ // `register('cms', …)` at `plugin.ts:90` which declared all 35 CMS names with
7
+ // `ownerModule: 'cms'` — five of which are `catalog`'s, so the descriptor
8
+ // answered the ownership question wrongly for every one of them and FR-010's
9
+ // presence filter had nothing true to key on. Ownership is now stated once, in
10
+ // the block's own `name`, by the module that owns it
11
+ // (`contracts/block-definition.md` §1 and §4.1).
12
+ //
13
+ // The registry is React-free: it stores metadata only. The render functions
14
+ // live in `@endora-commerce/cms-components` and the per-module packages, and
15
+ // the storefront imports them directly.
16
+ //
17
+ // ## Two things it deliberately does not do
18
+ //
19
+ // **It does not merge categories at registration.** A merge performed there has
20
+ // consumed composition order and can no longer answer differently when a module
21
+ // is switched off — which is the whole of B12. Declarations are kept keyed by
22
+ // their declaring module and folded at `describe()`, after the presence filter.
23
+ //
24
+ // **It applies no context admission.** `email` admitting into `newsletter` is
25
+ // the *palette* derivation's rule, applied once through `contextAdmits`
26
+ // (`contracts/block-definition.md` §4.1.1), so the wire shape keeps saying what
27
+ // the manifests say and exactly one layer answers "which sections does the
28
+ // newsletter palette have".
29
+ import { DEFAULT_BREAKPOINTS } from '@endora-commerce/page-builder-core/types/responsive';
30
+ /**
31
+ * Raised when two modules declare one block name.
32
+ *
33
+ * **D-31's collision requirement, and the reversal of defect D-d**: the old
34
+ * `register` warned and overwrote, which is last-writer-wins over a *persisted*
35
+ * identifier — one contributor's stored documents silently rendering as
36
+ * another's block. It has never been exercised because there was one
37
+ * contributor; there are now six.
38
+ *
39
+ * **Two contributors, never one registering twice.** The owner is compared, so
40
+ * a module re-declaring its own manifest is idempotent; a name that arrives
41
+ * from a second module id is the collision, and it is the only thing this error
42
+ * is for.
43
+ */
44
+ export class DuplicateBlockNameError extends Error {
45
+ constructor(name, first, second) {
46
+ super(`[cms/page-builder-registry] Block name "${name}" is declared by both "${first}" and ` +
47
+ `"${second}". A block name is persisted and must have one owner — rename one of the ` +
48
+ 'two declarations (`contracts/block-definition.md` §4.1).');
49
+ this.name = 'DuplicateBlockNameError';
50
+ }
51
+ }
52
+ export class PageBuilderRegistry {
53
+ components = new Map();
54
+ categories = [];
55
+ schemaVersion = 1;
56
+ breakpoints;
57
+ isModulePresent;
58
+ breakpointsResolver;
59
+ colorPaletteResolver;
60
+ constructor(options = {}) {
61
+ this.breakpoints = options.breakpoints ?? { ...DEFAULT_BREAKPOINTS };
62
+ this.isModulePresent = options.isModulePresent ?? (() => true);
63
+ for (const entry of options.manifests ?? []) {
64
+ this.registerManifest(entry.manifest);
65
+ }
66
+ }
67
+ /**
68
+ * Take one module's `blocks` and `blockCategories` declarations.
69
+ *
70
+ * The owner is the block name's first segment, which `defineModuleManifest`
71
+ * has already refused to let differ from the declaring module's `id`. It is
72
+ * read from the name rather than from the manifest so that the registry and
73
+ * the persisted document agree by construction.
74
+ */
75
+ registerManifest(manifest) {
76
+ for (const block of (manifest.blocks ?? [])) {
77
+ const existing = this.components.get(block.name);
78
+ // **The refusal's subject is two contributors**, which is what D-31 asks
79
+ // for and what defect D-d got wrong by warning and overwriting. One
80
+ // module registering twice — an idempotent re-composition, a harness
81
+ // calling a fixture once per test case — is not a collision, and refusing
82
+ // it produced the sentence `declared by both "x" and "x"`, which is
83
+ // self-evidently not one.
84
+ if (existing && existing.ownerModule !== manifest.id) {
85
+ throw new DuplicateBlockNameError(block.name, existing.ownerModule, manifest.id);
86
+ }
87
+ this.components.set(block.name, {
88
+ ownerModule: block.name.slice(0, block.name.indexOf('.')),
89
+ fields: block.fields,
90
+ contexts: [...block.contexts],
91
+ labelKey: block.labelKey,
92
+ ...(block.descriptionKey !== undefined ? { descriptionKey: block.descriptionKey } : {}),
93
+ category: block.category,
94
+ ...(block.defaultProps !== undefined ? { defaultProps: block.defaultProps } : {}),
95
+ ...(block.responsiveFields !== undefined
96
+ ? { responsiveFields: [...block.responsiveFields] }
97
+ : {}),
98
+ ...(block.previewIcon !== undefined ? { previewIcon: block.previewIcon } : {}),
99
+ ...(block.weight !== undefined ? { weight: block.weight } : {}),
100
+ });
101
+ }
102
+ for (const category of (manifest.blockCategories ?? [])) {
103
+ this.categories.push({ ...category, ownerModule: manifest.id });
104
+ }
105
+ }
106
+ setBreakpointsResolver(resolver) {
107
+ this.breakpointsResolver = resolver;
108
+ }
109
+ setColorPaletteResolver(resolver) {
110
+ this.colorPaletteResolver = resolver;
111
+ }
112
+ async resolveBreakpoints() {
113
+ if (this.breakpointsResolver) {
114
+ return this.breakpointsResolver();
115
+ }
116
+ return this.getBreakpoints();
117
+ }
118
+ isComponentRegistered(name) {
119
+ return this.components.has(name);
120
+ }
121
+ /**
122
+ * Every declared block name, **unfiltered by presence**.
123
+ *
124
+ * This answers "is this string a block name this platform knows", which the
125
+ * reference registries ask when they decide whether a stored node is a known
126
+ * embed. A switched-off module's blocks are still real names in stored
127
+ * documents, so filtering here would make a present document's node look
128
+ * unknown — a different question with a different right answer from the
129
+ * palette's.
130
+ */
131
+ knownNames() {
132
+ return new Set(this.components.keys());
133
+ }
134
+ getBreakpoints() {
135
+ return { ...this.breakpoints };
136
+ }
137
+ /**
138
+ * The metadata view used by `GET /api/v1/admin/cms/page-builder/config`.
139
+ *
140
+ * Filters to the effectively present modules and *then* folds the categories,
141
+ * in that order (`contracts/block-definition.md` §4.1). Both outputs are
142
+ * sorted by a function of the declarations alone, so the response is
143
+ * byte-identical under a re-composition or a reordering of `MODULES` — the
144
+ * D-45 property, which a fold at registration cannot have.
145
+ */
146
+ async describe() {
147
+ const breakpoints = await this.resolveBreakpoints();
148
+ const colorPalette = this.colorPaletteResolver ? await this.colorPaletteResolver() : [];
149
+ return {
150
+ schemaVersion: this.schemaVersion,
151
+ breakpoints,
152
+ colorPalette,
153
+ components: Array.from(this.components.entries())
154
+ .filter(([, reg]) => this.isModulePresent(reg.ownerModule))
155
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
156
+ .map(([name, reg]) => ({
157
+ name,
158
+ ownerModule: reg.ownerModule,
159
+ fields: reg.fields,
160
+ ...(reg.previewIcon !== undefined ? { previewIcon: reg.previewIcon } : {}),
161
+ contexts: reg.contexts ?? ['cms'],
162
+ ...(reg.labelKey !== undefined ? { labelKey: reg.labelKey } : {}),
163
+ ...(reg.descriptionKey !== undefined ? { descriptionKey: reg.descriptionKey } : {}),
164
+ ...(reg.category !== undefined ? { category: reg.category } : {}),
165
+ ...(reg.defaultProps !== undefined ? { defaultProps: reg.defaultProps } : {}),
166
+ ...(reg.responsiveFields !== undefined ? { responsiveFields: reg.responsiveFields } : {}),
167
+ ...(reg.weight !== undefined ? { weight: reg.weight } : {}),
168
+ })),
169
+ categories: this.foldCategories(),
170
+ };
171
+ }
172
+ /**
173
+ * Reduce every `(key, context)` group to one served record.
174
+ *
175
+ * `titleKey`, `weight` and `visible` come from **one** winning declaration and
176
+ * never field by field: a title from one module beside a weight from another
177
+ * is a presentation nobody wrote. The order is lowest `weight` first with an
178
+ * absent `weight` sorting after every declared one, ties broken by the
179
+ * declaring module's `id` ascending — a function of the declarations and of
180
+ * nothing else, so it is stable under re-composition
181
+ * (`contracts/block-definition.md` §1.1).
182
+ */
183
+ foldCategories() {
184
+ const groups = new Map();
185
+ for (const declaration of this.categories) {
186
+ if (!this.isModulePresent(declaration.ownerModule))
187
+ continue;
188
+ for (const context of declaration.contexts) {
189
+ const key = `${context} ${declaration.key}`;
190
+ const bucket = groups.get(key);
191
+ if (bucket)
192
+ bucket.push(declaration);
193
+ else
194
+ groups.set(key, [declaration]);
195
+ }
196
+ }
197
+ return [...groups.entries()]
198
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
199
+ .map(([key, declarations]) => {
200
+ const context = key.slice(0, key.indexOf(' '));
201
+ const winner = [...declarations].sort(compareCategoryDeclarations)[0];
202
+ return {
203
+ key: winner.key,
204
+ titleKey: winner.titleKey,
205
+ contexts: [context],
206
+ ...(winner.weight !== undefined ? { weight: winner.weight } : {}),
207
+ ...(winner.visible !== undefined ? { visible: winner.visible } : {}),
208
+ ownerModule: winner.ownerModule,
209
+ };
210
+ });
211
+ }
212
+ }
213
+ function compareCategoryDeclarations(a, b) {
214
+ const aw = a.weight ?? Number.POSITIVE_INFINITY;
215
+ const bw = b.weight ?? Number.POSITIVE_INFINITY;
216
+ if (aw !== bw)
217
+ return aw - bw;
218
+ return a.ownerModule < b.ownerModule ? -1 : a.ownerModule > b.ownerModule ? 1 : 0;
219
+ }
220
+ //# sourceMappingURL=page-builder-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-builder-registry.js","sourceRoot":"","sources":["../../../src/backend/services/page-builder-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ export interface SeededHook {
3
+ code: string;
4
+ name: string;
5
+ description?: string;
6
+ }
7
+ export declare const SEEDED_HOOKS: ReadonlyArray<SeededHook>;
8
+ export interface SeedHooksReconcileResult {
9
+ inserted: number;
10
+ preservedExisting: number;
11
+ }
12
+ /**
13
+ * Idempotent reconciler. Existing rows (matched by code) are preserved
14
+ * untouched — admin-edited names + descriptions survive every run.
15
+ * Missing seeded codes are inserted with `is_system=true`. Every seeded
16
+ * hook is also (re-)bound to every existing sales channel via
17
+ * `cms_hook_sales_channels` so the storefront's per-channel resolution
18
+ * sees the hook even after `sales_channels` was truncated (e.g. between
19
+ * test runs — the bindings cascade-deleted with the channels).
20
+ */
21
+ export declare function reconcileSeededHooks(emFactory: () => EntityManager): Promise<SeedHooksReconcileResult>;
22
+ //# sourceMappingURL=seed-hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed-hooks.d.ts","sourceRoot":"","sources":["../../../src/backend/services/seed-hooks.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAI3D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,YAAY,EAAE,aAAa,CAAC,UAAU,CA4BlD,CAAC;AAEF,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,aAAa,GAC7B,OAAO,CAAC,wBAAwB,CAAC,CA+CnC"}
@@ -0,0 +1,94 @@
1
+ // Seeded base Hook codes — feature 014 / R8 / T030.
2
+ //
3
+ // The 23 codes here are recognised natively by the storefront's named
4
+ // insertion points. The reconciler is idempotent: re-running it preserves
5
+ // admin-edited names + descriptions and re-creates a system Hook only if
6
+ // it is somehow missing. Runs at composition time before HTTP routes
7
+ // start serving (called from composition.ts), and inside the migration
8
+ // (035_cms_init.ts) so first boot doesn't race.
9
+ import { CmsHook } from '../entities/cms-hook.entity.js';
10
+ import { SalesChannel } from '@endora-commerce/platform/kernel';
11
+ export const SEEDED_HOOKS = [
12
+ {
13
+ code: 'header.top',
14
+ name: 'Header Top',
15
+ description: 'Top-of-page strip — phone number, free-shipping notice, etc.',
16
+ },
17
+ { code: 'homepage.top', name: 'Homepage Top', description: 'Above the homepage content.' },
18
+ { code: 'homepage.bottom', name: 'Homepage Bottom', description: 'Below the homepage content.' },
19
+ { code: 'footer.before', name: 'Footer Before' },
20
+ { code: 'footer.top', name: 'Footer Top' },
21
+ { code: 'footer.bottom', name: 'Footer Bottom' },
22
+ { code: 'footer.after', name: 'Footer After' },
23
+ { code: 'footer.copyright', name: 'Footer Copyright' },
24
+ { code: 'category.top', name: 'Category Page Top' },
25
+ { code: 'category.bottom', name: 'Category Page Bottom' },
26
+ { code: 'product.top', name: 'Product Page Top' },
27
+ { code: 'product.bottom', name: 'Product Page Bottom' },
28
+ { code: 'product.buttons.after', name: 'Product Page After Buttons Set' },
29
+ { code: 'search.top', name: 'Search Page Top' },
30
+ { code: 'search.bottom', name: 'Search Page Bottom' },
31
+ { code: 'page.top', name: 'Every Page Top' },
32
+ { code: 'page.bottom', name: 'Every Page Bottom' },
33
+ { code: 'cms.page.top', name: 'Every CMS Page Top' },
34
+ { code: 'cms.page.bottom', name: 'Every CMS Page Bottom' },
35
+ { code: 'login.top', name: 'Login Page Top' },
36
+ { code: 'login.bottom', name: 'Login Page Bottom' },
37
+ { code: 'register.top', name: 'Register Page Top' },
38
+ { code: 'register.bottom', name: 'Register Page Bottom' },
39
+ ];
40
+ /**
41
+ * Idempotent reconciler. Existing rows (matched by code) are preserved
42
+ * untouched — admin-edited names + descriptions survive every run.
43
+ * Missing seeded codes are inserted with `is_system=true`. Every seeded
44
+ * hook is also (re-)bound to every existing sales channel via
45
+ * `cms_hook_sales_channels` so the storefront's per-channel resolution
46
+ * sees the hook even after `sales_channels` was truncated (e.g. between
47
+ * test runs — the bindings cascade-deleted with the channels).
48
+ */
49
+ export async function reconcileSeededHooks(emFactory) {
50
+ // command-coverage-ignore: idempotent boot seed/reconcile of module-declared CMS
51
+ // hooks — a system-invariant repair, not an operator-initiated audited write.
52
+ const em = emFactory();
53
+ const existing = await em.find(CmsHook, { isSystem: true });
54
+ const existingByCode = new Map(existing.map((h) => [h.code, h]));
55
+ let inserted = 0;
56
+ for (const seed of SEEDED_HOOKS) {
57
+ if (existingByCode.has(seed.code))
58
+ continue;
59
+ const hook = em.create(CmsHook, {
60
+ name: seed.name,
61
+ code: seed.code,
62
+ active: true,
63
+ description: seed.description ?? null,
64
+ isSystem: true,
65
+ });
66
+ em.persist(hook);
67
+ inserted += 1;
68
+ }
69
+ if (inserted > 0)
70
+ await em.flush();
71
+ /**
72
+ * The channel ids come from the kernel's own entity, not from a
73
+ * `cross join "sales_channels"` (feature 075, D-87). `sales_channels` is the
74
+ * kernel's table since feature 072 moved the resolution machinery there, and
75
+ * a module relating into the kernel by ORM is the sanctioned access. The
76
+ * binding insert stays one set-based statement over this module's own two
77
+ * tables, with one ordinary binding per channel id.
78
+ */
79
+ const channelIds = (await em.find(SalesChannel, {}, { fields: ['id'] })).map((c) => c.id);
80
+ if (channelIds.length > 0) {
81
+ const channelValues = channelIds.map(() => '(?::uuid)').join(', ');
82
+ await em.execute(`insert into "cms_hook_sales_channels" ("hook_id", "sales_channel_id")
83
+ select h."id", c."id"
84
+ from "cms_hooks" h
85
+ cross join (values ${channelValues}) as c("id")
86
+ where h."is_system" = true
87
+ and not exists (
88
+ select 1 from "cms_hook_sales_channels" x
89
+ where x."hook_id" = h."id" and x."sales_channel_id" = c."id"
90
+ )`, channelIds);
91
+ }
92
+ return { inserted, preservedExisting: existing.length };
93
+ }
94
+ //# sourceMappingURL=seed-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed-hooks.js","sourceRoot":"","sources":["../../../src/backend/services/seed-hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import type { CmsAssetEmbedResolution, CmsPageIndexEntry, CmsResolvedBlock, CmsResolvedHook, CmsResolvedPage } from '@endora-commerce/contracts';
3
+ import type { CmsCache } from './cms-cache.js';
4
+ export type CmsAssetResolver = (assetId: string) => Promise<CmsAssetEmbedResolution | null>;
5
+ /**
6
+ * The request's resolved sales channel, handed in by the route from the
7
+ * canonical resolver, read via `getResolvedChannel()` — feature 053 / FR-002. The
8
+ * service no longer re-resolves the channel from the raw header.
9
+ */
10
+ export type ResolvedChannel = {
11
+ id: string;
12
+ code: string;
13
+ defaultLanguage: string;
14
+ };
15
+ export declare class StorefrontResolver {
16
+ private readonly emFactory;
17
+ private readonly cache?;
18
+ private assetResolver;
19
+ constructor(emFactory: () => EntityManager, cache?: CmsCache | undefined);
20
+ setAssetResolver(resolver: CmsAssetResolver | null): void;
21
+ private resolveAssetsForTrees;
22
+ resolvePageBySlug(input: {
23
+ resolvedChannel: ResolvedChannel;
24
+ language?: string | undefined;
25
+ slug: string;
26
+ }): Promise<CmsResolvedPage | null>;
27
+ /**
28
+ * Every published page of one sales channel, at the slug that channel serves
29
+ * it under (feature 105, FR-021; `contracts/cms-page-url.md` §4.1).
30
+ *
31
+ * The join is `resolvePageBySlug`'s, minus the slug predicate: same table,
32
+ * same three conditions — the channel binding, `status = 'published'` and
33
+ * `active = true` — so a page this answer names is a page that endpoint
34
+ * serves, and a page it omits is one that would 404. A sitemap built from a
35
+ * looser query would advertise a URL the shop refuses, which is the state §4.1
36
+ * exists to make unreachable.
37
+ *
38
+ * The slug comes off `cms_page_sales_channels`, never off `cms_pages`: the
39
+ * address is per channel (Constitution XII), and the page row's own column is
40
+ * one value shared by all of them.
41
+ *
42
+ * Uncached, deliberately. `CmsCache` keys a page by `(slug, channel, language)`
43
+ * and is invalidated per slug on write, so an index cached beside it would
44
+ * survive every invalidation the module performs and go stale on the first
45
+ * publish. The read is one indexed join per sitemap build, which Next's own
46
+ * route cache already sits in front of.
47
+ */
48
+ listPublishedPages(input: {
49
+ resolvedChannel: ResolvedChannel;
50
+ }): Promise<CmsPageIndexEntry[]>;
51
+ resolveBlockByCode(input: {
52
+ resolvedChannel: ResolvedChannel;
53
+ language?: string | undefined;
54
+ code: string;
55
+ }): Promise<CmsResolvedBlock | null>;
56
+ resolveHookByCode(input: {
57
+ resolvedChannel: ResolvedChannel;
58
+ language?: string | undefined;
59
+ code: string;
60
+ }): Promise<CmsResolvedHook | null>;
61
+ /**
62
+ * Recursively inlines InsertBlock / InsertTemplate references found in the
63
+ * supplied Page Builder data tree. Capped at EMBED_DEPTH_CAP levels —
64
+ * cycles or deeper graphs degrade to placeholders rendered admin-side.
65
+ */
66
+ private inlineEmbeds;
67
+ private fetchBlocksByCodes;
68
+ private fetchTemplatesByCodes;
69
+ private resolveLanguage;
70
+ }
71
+ //# sourceMappingURL=storefront-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storefront-resolver.d.ts","sourceRoot":"","sources":["../../../src/backend/services/storefront-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EACV,uBAAuB,EACvB,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,eAAe,EAEhB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAAC;AAiC5F;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AA0BF,qBAAa,kBAAkB;IAI3B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IAJzB,OAAO,CAAC,aAAa,CAAiC;gBAGnC,SAAS,EAAE,MAAM,aAAa,EAC9B,KAAK,CAAC,EAAE,QAAQ,YAAA;IAGnC,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI;YAI3C,qBAAqB;IAkB7B,iBAAiB,CAAC,KAAK,EAAE;QAC7B,eAAe,EAAE,eAAe,CAAC;QACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC9B,IAAI,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IA0DnC;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,kBAAkB,CAAC,KAAK,EAAE;QAC9B,eAAe,EAAE,eAAe,CAAC;KAClC,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAoB1B,kBAAkB,CAAC,KAAK,EAAE;QAC9B,eAAe,EAAE,eAAe,CAAC;QACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC9B,IAAI,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAwC9B,iBAAiB,CAAC,KAAK,EAAE;QAC7B,eAAe,EAAE,eAAe,CAAC;QACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC9B,IAAI,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAuEnC;;;;OAIG;YACW,YAAY;YA0EZ,kBAAkB;YAkBlB,qBAAqB;IAiBnC,OAAO,CAAC,eAAe;CA6BxB"}