@designcrowd/library.brand-page 5.17.6 → 5.17.7

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 (172) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-BI2KuOEF.js → CreatedOnBrandCrowd-de-de-BUQFMhZb.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-BYLJCjLJ.js → CreatedOnBrandCrowd-en-us-QS-5r4XI.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-Y_D6cuGE.js → CreatedOnBrandCrowd-es-es-CP2iH-n0.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-CqCBRjYh.js → CreatedOnBrandCrowd-fr-ca-qfD4NmQZ.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-CqCBRjYh.js → CreatedOnBrandCrowd-fr-fr-qfD4NmQZ.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-Bt0YF6DA.js → CreatedOnBrandCrowd-pt-br-CfmaB7zE.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-Bt0YF6DA.js → CreatedOnBrandCrowd-pt-pt-CfmaB7zE.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-CEk8FBEG.js → CreatedOnDcom-de-de-BxSUWfGN.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-DWw4Tm2L.js → CreatedOnDcom-en-us-CSeUdR6v.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-DpG-8o98.js → CreatedOnDcom-es-es-g7rCfAtP.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-CEla7RmR.js → CreatedOnDcom-fr-ca-Bh_BTb-O.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-DRXeVTlV.js → CreatedOnDcom-fr-fr-Clgd_Ujm.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-Bzu_phZc.js → CreatedOnDcom-pt-br-Dlgk0myX.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-DWax8Er7.js → CreatedOnDcom-pt-pt-B14APfrn.js} +1 -1
  15. package/lib/src/brand-page/models/brand-page-context.model.d.ts +2 -1
  16. package/lib/src/brand-page/models/brand-page-context.model.js +5 -0
  17. package/lib/src/brand-page/models/index.d.ts +1 -0
  18. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +62 -2
  19. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +1 -0
  20. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +60 -2
  21. package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +30 -1
  22. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +60 -2
  23. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +60 -2
  24. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +60 -2
  25. package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +60 -2
  26. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +60 -2
  27. package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +60 -2
  28. package/lib/src/brand-page-maker/composables/ai-chat/useAiChat.js +3 -1
  29. package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.d.ts +1 -1
  30. package/lib/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.js +6 -6
  31. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.d.ts +2 -0
  32. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +258 -0
  33. package/lib/src/brand-page-maker/constants/sidebar-constant.d.ts +1 -0
  34. package/lib/src/brand-page-maker/constants/sidebar-constant.js +8 -0
  35. package/lib/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.d.ts +16 -0
  36. package/lib/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.js +14 -0
  37. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +62 -3
  38. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +2 -0
  39. package/lib/src/brand-page-maker/stores/index.d.ts +1 -0
  40. package/lib/src/brand-page-maker/stores/index.js +1 -0
  41. package/lib/src/brand-page-maker/stores/snapshot/snapshot-store.d.ts +2 -0
  42. package/lib/src/brand-page-maker/stores/snapshot/snapshot-store.js +9 -0
  43. package/lib/src/clients/ai-assistant-client.d.ts +8 -0
  44. package/lib/src/clients/ai-assistant-client.js +11 -1
  45. package/lib/src/composables/useSnapshot.js +33 -0
  46. package/lib/src/css/library.brand-page-brandCrowd.min.css +19 -6
  47. package/lib/src/css/library.brand-page-brandPage.min.css +19 -6
  48. package/lib/src/css/library.brand-page-designCom.min.css +19 -6
  49. package/lib/src/css/library.brand-page-preview.min.css +19 -6
  50. package/lib/src/index.d.ts +1 -0
  51. package/lib/src/index.mjs +42 -41
  52. package/lib/src/{lib-DODSa6QK.js → lib-pOkCQP0J.js} +28820 -26841
  53. package/lib/src/lib.js +1 -0
  54. package/lib/src/metadata-builder/ai-metadata-executor.d.ts +1 -1
  55. package/lib/src/metadata-builder/ai-metadata-executor.js +68 -7
  56. package/lib/src/metadata-builder/builders/add-page-builder.d.ts +14 -0
  57. package/lib/src/metadata-builder/builders/add-page-builder.js +66 -0
  58. package/lib/src/metadata-builder/builders/remove-page-builder.d.ts +13 -0
  59. package/lib/src/metadata-builder/builders/remove-page-builder.js +50 -0
  60. package/lib/src/metadata-builder/builders/section-builders/about-section-builder.d.ts +6 -0
  61. package/lib/src/metadata-builder/builders/section-builders/about-section-builder.js +17 -0
  62. package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.d.ts +6 -0
  63. package/lib/src/metadata-builder/builders/section-builders/banner-section-builder.js +25 -0
  64. package/lib/src/metadata-builder/builders/section-builders/base-section-builder.d.ts +40 -0
  65. package/lib/src/metadata-builder/builders/section-builders/base-section-builder.js +108 -0
  66. package/lib/src/metadata-builder/builders/section-builders/button-section-builder.d.ts +6 -0
  67. package/lib/src/metadata-builder/builders/section-builders/button-section-builder.js +16 -0
  68. package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.d.ts +6 -0
  69. package/lib/src/metadata-builder/builders/section-builders/contact-form-builder.js +27 -0
  70. package/lib/src/metadata-builder/builders/section-builders/delete-section-builder.d.ts +13 -0
  71. package/lib/src/metadata-builder/builders/section-builders/delete-section-builder.js +37 -0
  72. package/lib/src/metadata-builder/builders/section-builders/divider-section-builder.d.ts +6 -0
  73. package/lib/src/metadata-builder/builders/section-builders/divider-section-builder.js +16 -0
  74. package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.d.ts +6 -0
  75. package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.js +76 -0
  76. package/lib/src/metadata-builder/builders/section-builders/image-section-builder.d.ts +6 -0
  77. package/lib/src/metadata-builder/builders/section-builders/image-section-builder.js +16 -0
  78. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.d.ts +6 -0
  79. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +158 -0
  80. package/lib/src/metadata-builder/builders/section-builders/index.d.ts +17 -0
  81. package/lib/src/metadata-builder/builders/section-builders/index.js +17 -0
  82. package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.d.ts +6 -0
  83. package/lib/src/metadata-builder/builders/section-builders/mailing-list-builder.js +17 -0
  84. package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.d.ts +6 -0
  85. package/lib/src/metadata-builder/builders/section-builders/mailing-list-section-builder.js +16 -0
  86. package/lib/src/metadata-builder/builders/section-builders/move-section-builder.d.ts +15 -0
  87. package/lib/src/metadata-builder/builders/section-builders/move-section-builder.js +62 -0
  88. package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.d.ts +6 -0
  89. package/lib/src/metadata-builder/builders/section-builders/profile-section-builder.js +16 -0
  90. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.d.ts +6 -0
  91. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +162 -0
  92. package/lib/src/metadata-builder/builders/section-builders/social-links-builder.d.ts +6 -0
  93. package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +50 -0
  94. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.d.ts +6 -0
  95. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +133 -0
  96. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.d.ts +6 -0
  97. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +154 -0
  98. package/lib/src/metadata-builder/builders/section-content-factory.d.ts +3 -0
  99. package/lib/src/metadata-builder/builders/section-content-factory.js +13 -0
  100. package/lib/src/metadata-builder/builders/section-field-maps.d.ts +12 -0
  101. package/lib/src/metadata-builder/builders/section-field-maps.js +180 -0
  102. package/lib/src/metadata-builder/builders/section-field-utils.d.ts +11 -0
  103. package/lib/src/metadata-builder/builders/section-field-utils.js +109 -0
  104. package/lib/src/metadata-builder/helpers/rte.helpers.d.ts +6 -0
  105. package/lib/src/metadata-builder/helpers/rte.helpers.js +16 -1
  106. package/lib/src/metadata-builder/metadata-executor.js +71 -1
  107. package/lib/src/metadata-builder/models.d.ts +54 -0
  108. package/lib/src/metadata-builder/models.js +58 -0
  109. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +51 -3
  110. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.js +110 -13
  111. package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +285 -0
  112. package/lib/src/metadata-builder/parsers/section-tool-arguments.js +7 -0
  113. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +60 -2
  114. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +60 -2
  115. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +60 -2
  116. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +60 -2
  117. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +90 -3
  118. package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +61 -2
  119. package/lib/src/shared/side-bar/components/SideBar.mixin.js +6 -0
  120. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +60 -2
  121. package/lib/src/utils/minify-brand-page-metadata.d.ts +22 -0
  122. package/lib/src/utils/minify-brand-page-metadata.js +344 -0
  123. package/package.json +1 -1
  124. package/src/brand-page/models/brand-page-context.model.ts +12 -3
  125. package/src/brand-page/models/index.ts +1 -0
  126. package/src/brand-page-maker/components/ai-website-builder/AiWebsiteBuilder.vue +80 -0
  127. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +4 -0
  128. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.vue +9 -2
  129. package/src/brand-page-maker/composables/ai-chat/useAiChat.ts +4 -1
  130. package/src/brand-page-maker/composables/ai-chat/useAiMetadataBuilder.ts +6 -6
  131. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +363 -0
  132. package/src/brand-page-maker/constants/sidebar-constant.ts +8 -0
  133. package/src/brand-page-maker/stores/ai-thread/ai-website-builder-thread-store.ts +19 -0
  134. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +3 -1
  135. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +4 -0
  136. package/src/brand-page-maker/stores/index.ts +1 -0
  137. package/src/brand-page-maker/stores/snapshot/snapshot-store.ts +12 -0
  138. package/src/clients/ai-assistant-client.ts +17 -1
  139. package/src/composables/useSnapshot.ts +47 -0
  140. package/src/lib.ts +4 -0
  141. package/src/metadata-builder/ai-metadata-executor.ts +116 -26
  142. package/src/metadata-builder/builders/add-page-builder.ts +98 -0
  143. package/src/metadata-builder/builders/remove-page-builder.ts +83 -0
  144. package/src/metadata-builder/builders/section-builders/about-section-builder.ts +28 -0
  145. package/src/metadata-builder/builders/section-builders/banner-section-builder.ts +45 -0
  146. package/src/metadata-builder/builders/section-builders/base-section-builder.ts +160 -0
  147. package/src/metadata-builder/builders/section-builders/button-section-builder.ts +24 -0
  148. package/src/metadata-builder/builders/section-builders/contact-form-builder.ts +43 -0
  149. package/src/metadata-builder/builders/section-builders/delete-section-builder.ts +63 -0
  150. package/src/metadata-builder/builders/section-builders/divider-section-builder.ts +27 -0
  151. package/src/metadata-builder/builders/section-builders/image-gallery-builder.ts +111 -0
  152. package/src/metadata-builder/builders/section-builders/image-section-builder.ts +24 -0
  153. package/src/metadata-builder/builders/section-builders/images-section-builder.ts +223 -0
  154. package/src/metadata-builder/builders/section-builders/index.ts +21 -0
  155. package/src/metadata-builder/builders/section-builders/mailing-list-builder.ts +29 -0
  156. package/src/metadata-builder/builders/section-builders/mailing-list-section-builder.ts +27 -0
  157. package/src/metadata-builder/builders/section-builders/move-section-builder.ts +100 -0
  158. package/src/metadata-builder/builders/section-builders/profile-section-builder.ts +27 -0
  159. package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +231 -0
  160. package/src/metadata-builder/builders/section-builders/social-links-builder.ts +79 -0
  161. package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +194 -0
  162. package/src/metadata-builder/builders/section-builders/text-section-builder.ts +234 -0
  163. package/src/metadata-builder/builders/section-content-factory.ts +20 -0
  164. package/src/metadata-builder/builders/section-field-maps.ts +235 -0
  165. package/src/metadata-builder/builders/section-field-utils.ts +157 -0
  166. package/src/metadata-builder/helpers/rte.helpers.ts +23 -1
  167. package/src/metadata-builder/metadata-executor.ts +96 -4
  168. package/src/metadata-builder/models.ts +62 -0
  169. package/src/metadata-builder/parsers/ai-toolcall-parser.ts +141 -17
  170. package/src/metadata-builder/parsers/section-tool-arguments.ts +417 -0
  171. package/src/shared/side-bar/components/SideBar.mixin.ts +10 -0
  172. package/src/utils/minify-brand-page-metadata.ts +407 -0
package/lib/src/lib.js CHANGED
@@ -25,6 +25,7 @@ export { default as CookieConsent } from './brand-page/components/cookie-consent
25
25
  export { default as SensitiveContentModal } from './brand-page/components/sensitive-content/SensitiveContentModal.vue';
26
26
  // functions
27
27
  export { getBrandPageViewModelFromBrandPageModel, migrateBrandPageModel, } from './brand-page/utils';
28
+ export { minifyBrandPageMetadata, } from './utils/minify-brand-page-metadata';
28
29
  export * as brandPageUtils from './brand-page/utils';
29
30
  export { getOptimalLogoSize, calculateOptimizedLogoDimensions, applyLogoImageBase64UrlToBrandPageTemplateModel, recalculateLogoContentDimensions, recalculateHeaderLogoSizes, } from './brand-page/utils/logo.util';
30
31
  export { sanitizeRTEHtml } from './brand-page-maker/utils';
@@ -2,7 +2,7 @@ import { type BrandPageModel } from '../brand-page/models';
2
2
  import type { Logger } from './logger';
3
3
  import { type MetadataExecutorResult } from './models';
4
4
  import { type ParsedToolCall } from './parsers/ai-toolcall-parser';
5
- export declare const executeAiToolUseAsync: (metadata: BrandPageModel, toolcalls: ParsedToolCall[], options: {
5
+ export declare const executeToolCallsAsync: (metadata: BrandPageModel, toolcalls: ParsedToolCall[], options: {
6
6
  logger?: Logger;
7
7
  maxCharacters?: number;
8
8
  }) => Promise<MetadataExecutorResult>;
@@ -2,10 +2,11 @@ import {} from '../brand-page/models';
2
2
  import { buildUpdateTextRequest } from './builders/update-content-text-builder';
3
3
  import { buildUpdateTextStyleRequest } from './builders/update-content-text-style-builder';
4
4
  import { MetadataExecutor } from './metadata-executor';
5
- import {} from './models';
6
- import { AI_ASSISTANT_TOOL_NAMES, } from './parsers/ai-toolcall-parser';
7
- export const executeAiToolUseAsync = async (metadata, toolcalls, options) => {
8
- const requests = toolcalls.map((toolcall) => {
5
+ import { BUILDER_TYPES, } from './models';
6
+ import { AI_ASSISTANT_TOOL_NAMES, SECTION_TOOL_MAP, } from './parsers/ai-toolcall-parser';
7
+ export const executeToolCallsAsync = async (metadata, toolcalls, options) => {
8
+ const requests = toolcalls
9
+ .map((toolcall) => {
9
10
  switch (toolcall.function) {
10
11
  case AI_ASSISTANT_TOOL_NAMES.UPDATE_TEXT: {
11
12
  const arg = toolcall.arguments;
@@ -24,12 +25,72 @@ export const executeAiToolUseAsync = async (metadata, toolcalls, options) => {
24
25
  newStyles: arg.metadata.style,
25
26
  });
26
27
  }
28
+ case AI_ASSISTANT_TOOL_NAMES.DELETE_SECTION: {
29
+ const arg = toolcall.arguments;
30
+ return {
31
+ id: toolcall.toolId,
32
+ type: BUILDER_TYPES.DELETE_SECTION,
33
+ payload: {
34
+ contentId: arg.content_id,
35
+ },
36
+ };
37
+ }
38
+ case AI_ASSISTANT_TOOL_NAMES.MOVE_SECTION: {
39
+ const arg = toolcall.arguments;
40
+ return {
41
+ id: toolcall.toolId,
42
+ type: BUILDER_TYPES.MOVE_SECTION,
43
+ payload: {
44
+ contentId: arg.content_id,
45
+ position: arg.position,
46
+ targetPageId: arg.target_page_id,
47
+ },
48
+ };
49
+ }
50
+ case AI_ASSISTANT_TOOL_NAMES.ADD_PAGE: {
51
+ const arg = toolcall.arguments;
52
+ return {
53
+ id: toolcall.toolId,
54
+ type: BUILDER_TYPES.ADD_PAGE,
55
+ payload: {
56
+ pageId: arg.page_id,
57
+ pageName: arg.page_name,
58
+ },
59
+ };
60
+ }
61
+ case AI_ASSISTANT_TOOL_NAMES.REMOVE_PAGE: {
62
+ const arg = toolcall.arguments;
63
+ return {
64
+ id: toolcall.toolId,
65
+ type: BUILDER_TYPES.REMOVE_PAGE,
66
+ payload: {
67
+ pageId: arg.page_id,
68
+ },
69
+ };
70
+ }
27
71
  default: {
28
- throw new Error(`Unsupported tool call: ${toolcall.function}`);
72
+ const sectionTool = SECTION_TOOL_MAP[toolcall.function];
73
+ if (!sectionTool) {
74
+ console.warn(`[executeToolCallsAsync] Skipping unsupported tool call: ${toolcall.function}`);
75
+ return null;
76
+ }
77
+ const { mode, content_id: contentId, page_id: pageId, arguments: sectionArgs, } = toolcall.arguments;
78
+ const builderType = `${mode}-${sectionTool.sectionType}`;
79
+ return {
80
+ id: toolcall.toolId,
81
+ type: builderType,
82
+ payload: {
83
+ sectionType: sectionTool.sectionType,
84
+ contentId: contentId,
85
+ arguments: sectionArgs,
86
+ pageId: pageId,
87
+ },
88
+ };
29
89
  }
30
90
  }
31
- });
32
- options.logger?.log('executeAiToolUseAsync', { requests });
91
+ })
92
+ .filter((r) => r !== null);
93
+ options.logger?.log('executeToolCallsAsync', { requests });
33
94
  const executor = new MetadataExecutor();
34
95
  return await executor.executeAsync(metadata, requests, options.logger);
35
96
  };
@@ -0,0 +1,14 @@
1
+ import { type BrandPageModel } from '../../brand-page/models';
2
+ import { BaseMetadataBuilder, type BuilderResult, type MetadataBuilderRequest } from '../models';
3
+ import type { Logger } from '../logger';
4
+ export interface AddPagePayload {
5
+ pageId: string;
6
+ pageName: string;
7
+ }
8
+ export declare class AddPageBuilder extends BaseMetadataBuilder<AddPagePayload> {
9
+ constructor(request: MetadataBuilderRequest<AddPagePayload>, logger?: Logger);
10
+ validateAsync(): Promise<{
11
+ errors: string[];
12
+ }>;
13
+ buildAsync(model: BrandPageModel): Promise<BuilderResult>;
14
+ }
@@ -0,0 +1,66 @@
1
+ import { PageModel } from '../../brand-page/models';
2
+ import { getPageSlugFromPageTitle } from '../../brand-page-maker/utils/slug.util';
3
+ import { BaseMetadataBuilder, } from '../models';
4
+ export class AddPageBuilder extends BaseMetadataBuilder {
5
+ constructor(request, logger) {
6
+ super(request, logger);
7
+ }
8
+ async validateAsync() {
9
+ const errors = [];
10
+ const payload = this.request.payload;
11
+ if (!payload?.pageId) {
12
+ errors.push('page_id is required for add_page');
13
+ }
14
+ if (!payload?.pageName) {
15
+ errors.push('page_name is required for add_page');
16
+ }
17
+ return { errors };
18
+ }
19
+ async buildAsync(model) {
20
+ this.log('Build called');
21
+ const validation = await this.validateAsync();
22
+ if (validation.errors.length) {
23
+ return { request: this.request, model, errors: validation.errors };
24
+ }
25
+ const { pageId, pageName } = this.request.payload;
26
+ // Check if page with this ID already exists
27
+ if (model.pages.some((p) => p.id === pageId)) {
28
+ return {
29
+ request: this.request,
30
+ model,
31
+ errors: [`Page with ID "${pageId}" already exists`],
32
+ };
33
+ }
34
+ // Create the new page
35
+ const newPage = new PageModel({
36
+ id: pageId,
37
+ title: pageName,
38
+ contents: [],
39
+ isHidden: false,
40
+ });
41
+ // Insert the new page before any hidden pages
42
+ const visiblePages = model.pages.filter((page) => !page.isHidden);
43
+ const hiddenPages = model.pages.filter((page) => page.isHidden);
44
+ model.pages = [...visiblePages, newPage, ...hiddenPages];
45
+ // Construct slug from page name, ensuring uniqueness against existing routes
46
+ const existingSlugs = model.nav.routes.map((r) => r.pageSlug);
47
+ const slug = getPageSlugFromPageTitle(pageName, existingSlugs);
48
+ // Add nav route and order entry
49
+ const routeId = `route-${pageId}`;
50
+ model.nav.routes.push({
51
+ id: routeId,
52
+ pageId,
53
+ pageSlug: slug,
54
+ isHidden: false,
55
+ displayName: pageName,
56
+ });
57
+ model.nav.orders.push({
58
+ routeId,
59
+ subRoutes: [],
60
+ });
61
+ this.log({
62
+ message: `Added page "${pageName}" (${pageId}) with slug "/${slug}"`,
63
+ });
64
+ return { request: this.request, model };
65
+ }
66
+ }
@@ -0,0 +1,13 @@
1
+ import { type BrandPageModel } from '../../brand-page/models';
2
+ import { BaseMetadataBuilder, type BuilderResult, type MetadataBuilderRequest } from '../models';
3
+ import type { Logger } from '../logger';
4
+ export interface RemovePagePayload {
5
+ pageId: string;
6
+ }
7
+ export declare class RemovePageBuilder extends BaseMetadataBuilder<RemovePagePayload> {
8
+ constructor(request: MetadataBuilderRequest<RemovePagePayload>, logger?: Logger);
9
+ validateAsync(): Promise<{
10
+ errors: string[];
11
+ }>;
12
+ buildAsync(model: BrandPageModel): Promise<BuilderResult>;
13
+ }
@@ -0,0 +1,50 @@
1
+ import {} from '../../brand-page/models';
2
+ import { BaseMetadataBuilder, } from '../models';
3
+ export class RemovePageBuilder extends BaseMetadataBuilder {
4
+ constructor(request, logger) {
5
+ super(request, logger);
6
+ }
7
+ async validateAsync() {
8
+ const errors = [];
9
+ const payload = this.request.payload;
10
+ if (!payload?.pageId) {
11
+ errors.push('page_id is required for remove_page');
12
+ }
13
+ return { errors };
14
+ }
15
+ async buildAsync(model) {
16
+ this.log('Build called');
17
+ const validation = await this.validateAsync();
18
+ if (validation.errors.length) {
19
+ return { request: this.request, model, errors: validation.errors };
20
+ }
21
+ const { pageId } = this.request.payload;
22
+ // Check if page exists
23
+ const pageIndex = model.pages.findIndex((p) => p.id === pageId);
24
+ if (pageIndex === -1) {
25
+ return {
26
+ request: this.request,
27
+ model,
28
+ errors: [`Page with ID "${pageId}" not found`],
29
+ };
30
+ }
31
+ const page = model.pages[pageIndex];
32
+ // Remove the page
33
+ model.pages.splice(pageIndex, 1);
34
+ // Remove matching nav route(s)
35
+ const removedRouteIds = new Set();
36
+ model.nav.routes = model.nav.routes.filter((route) => {
37
+ if (route.pageId === pageId) {
38
+ removedRouteIds.add(route.id);
39
+ return false;
40
+ }
41
+ return true;
42
+ });
43
+ // Remove matching nav order entries
44
+ model.nav.orders = model.nav.orders.filter((order) => !removedRouteIds.has(order.routeId));
45
+ this.log({
46
+ message: `Removed page "${page.title}" (${pageId})`,
47
+ });
48
+ return { request: this.request, model };
49
+ }
50
+ }
@@ -0,0 +1,6 @@
1
+ import type { AboutSectionContent, BrandPageModel } from '../../../brand-page/models';
2
+ import type { BuilderResult } from '../../models';
3
+ import { BaseSectionBuilder } from './base-section-builder';
4
+ export declare class AboutSectionBuilder extends BaseSectionBuilder<AboutSectionContent> {
5
+ buildAsync(model: BrandPageModel): Promise<BuilderResult>;
6
+ }
@@ -0,0 +1,17 @@
1
+ import { applyScalarFields, applyStyleFields } from '../section-field-utils';
2
+ import { BaseSectionBuilder } from './base-section-builder';
3
+ export class AboutSectionBuilder extends BaseSectionBuilder {
4
+ async buildAsync(model) {
5
+ this.log('Build called');
6
+ const validation = await this.validateAsync();
7
+ if (validation.errors.length) {
8
+ return { request: this.request, model, errors: validation.errors };
9
+ }
10
+ const resolved = this.resolveContent(model);
11
+ if ('error' in resolved)
12
+ return resolved.error;
13
+ applyScalarFields(resolved.content, this.args, this.sectionType);
14
+ applyStyleFields(resolved.content, this.args, this.sectionType);
15
+ return { request: this.request, model };
16
+ }
17
+ }
@@ -0,0 +1,6 @@
1
+ import type { BannerSectionContent, BrandPageModel } from '../../../brand-page/models';
2
+ import type { BuilderResult } from '../../models';
3
+ import { BaseSectionBuilder } from './base-section-builder';
4
+ export declare class BannerSectionBuilder extends BaseSectionBuilder<BannerSectionContent> {
5
+ buildAsync(model: BrandPageModel): Promise<BuilderResult>;
6
+ }
@@ -0,0 +1,25 @@
1
+ import { applyScalarFields, applyStyleFields, applyRTEStyles, } from '../section-field-utils';
2
+ import { BaseSectionBuilder } from './base-section-builder';
3
+ const applyBackgroundImage = (content, args) => {
4
+ if (args.background_image_url) {
5
+ content.media = undefined;
6
+ content.mediaType = 'image';
7
+ }
8
+ };
9
+ export class BannerSectionBuilder extends BaseSectionBuilder {
10
+ async buildAsync(model) {
11
+ this.log('Build called');
12
+ const validation = await this.validateAsync();
13
+ if (validation.errors.length) {
14
+ return { request: this.request, model, errors: validation.errors };
15
+ }
16
+ const resolved = this.resolveContent(model);
17
+ if ('error' in resolved)
18
+ return resolved.error;
19
+ applyScalarFields(resolved.content, this.args, this.sectionType);
20
+ applyStyleFields(resolved.content, this.args, this.sectionType);
21
+ applyRTEStyles(resolved.content, this.args, this.sectionType);
22
+ applyBackgroundImage(resolved.content, this.args);
23
+ return { request: this.request, model };
24
+ }
25
+ }
@@ -0,0 +1,40 @@
1
+ import { type BrandPageModel, type Content } from '../../../brand-page/models';
2
+ import type { Logger } from '../../logger';
3
+ import { BaseMetadataBuilder, type BuilderResult, type MetadataBuilderRequest } from '../../models';
4
+ import type { SectionToolArguments, SectionType } from '../../parsers/section-tool-arguments';
5
+ export interface SectionBuilderPayload {
6
+ sectionType: SectionType;
7
+ arguments: SectionToolArguments;
8
+ /** Only required for update operations. */
9
+ contentId?: string;
10
+ /** Target page ID — used for create operations to place the new section on the correct page. */
11
+ pageId?: string;
12
+ }
13
+ /**
14
+ * Abstract base for per-section builders.
15
+ *
16
+ * Concrete builders implement `buildAsync` directly, using
17
+ * `resolveContent()` to obtain the content object to mutate.
18
+ */
19
+ export declare abstract class BaseSectionBuilder<C extends Content = Content> extends BaseMetadataBuilder<SectionBuilderPayload> {
20
+ constructor(request: MetadataBuilderRequest<SectionBuilderPayload>, logger?: Logger);
21
+ protected get sectionType(): SectionType;
22
+ protected get mode(): 'create' | 'update';
23
+ protected get args(): SectionToolArguments;
24
+ /** Override in subclasses for per-section validation. */
25
+ protected validateSection(): string[];
26
+ validateAsync(): Promise<{
27
+ errors: string[];
28
+ }>;
29
+ /**
30
+ * Validates the request, then creates or finds the target content.
31
+ * Returns `{ content }` on success, or `{ error }` with a BuilderResult on failure.
32
+ */
33
+ protected resolveContent(model: BrandPageModel): {
34
+ content: C;
35
+ } | {
36
+ error: BuilderResult;
37
+ };
38
+ private createContent;
39
+ private findContent;
40
+ }
@@ -0,0 +1,108 @@
1
+ import {} from '../../../brand-page/models';
2
+ import { BaseMetadataBuilder, } from '../../models';
3
+ import { createDefaultSectionContent } from '../section-content-factory';
4
+ /**
5
+ * Abstract base for per-section builders.
6
+ *
7
+ * Concrete builders implement `buildAsync` directly, using
8
+ * `resolveContent()` to obtain the content object to mutate.
9
+ */
10
+ export class BaseSectionBuilder extends BaseMetadataBuilder {
11
+ constructor(request, logger) {
12
+ super(request, logger);
13
+ }
14
+ get sectionType() {
15
+ return this.request.payload.sectionType;
16
+ }
17
+ get mode() {
18
+ return this.request.type.startsWith('create-') ? 'create' : 'update';
19
+ }
20
+ get args() {
21
+ return this.request.payload.arguments;
22
+ }
23
+ /** Override in subclasses for per-section validation. */
24
+ validateSection() {
25
+ return [];
26
+ }
27
+ async validateAsync() {
28
+ const errors = [];
29
+ const payload = this.request.payload;
30
+ if (this.mode === 'create') {
31
+ if (!createDefaultSectionContent(payload.sectionType)) {
32
+ errors.push(`Unsupported section type: "${payload.sectionType}"`);
33
+ }
34
+ }
35
+ if (this.mode === 'update') {
36
+ if (!payload.contentId) {
37
+ errors.push('contentId is required for update operations');
38
+ }
39
+ }
40
+ errors.push(...this.validateSection());
41
+ return { errors };
42
+ }
43
+ /**
44
+ * Validates the request, then creates or finds the target content.
45
+ * Returns `{ content }` on success, or `{ error }` with a BuilderResult on failure.
46
+ */
47
+ resolveContent(model) {
48
+ if (this.mode === 'create') {
49
+ return this.createContent(model);
50
+ }
51
+ return this.findContent(model);
52
+ }
53
+ createContent(model) {
54
+ const payload = this.request.payload;
55
+ const { pageId } = payload;
56
+ const content = createDefaultSectionContent(this.sectionType);
57
+ if (!content) {
58
+ return {
59
+ error: {
60
+ request: this.request,
61
+ model,
62
+ errors: [
63
+ `Failed to create default content for section type: "${this.sectionType}"`,
64
+ ],
65
+ },
66
+ };
67
+ }
68
+ const targetPage = pageId
69
+ ? model.pages.find((p) => p.id === pageId)
70
+ : model.pages[0];
71
+ if (!targetPage) {
72
+ return {
73
+ error: {
74
+ request: this.request,
75
+ model,
76
+ errors: [
77
+ pageId
78
+ ? `Page with ID "${pageId}" not found`
79
+ : 'No pages found in model',
80
+ ],
81
+ },
82
+ };
83
+ }
84
+ targetPage.contents.push(content);
85
+ this.log({
86
+ message: `Created ${this.sectionType} section on page ${targetPage.id}`,
87
+ contentId: content.id,
88
+ });
89
+ return { content: content };
90
+ }
91
+ findContent(model) {
92
+ const { contentId } = this.request.payload;
93
+ for (const page of model.pages) {
94
+ for (const content of page.contents) {
95
+ if (content.id === contentId) {
96
+ return { content: content };
97
+ }
98
+ }
99
+ }
100
+ return {
101
+ error: {
102
+ request: this.request,
103
+ model,
104
+ errors: [`Content with ID "${contentId}" not found`],
105
+ },
106
+ };
107
+ }
108
+ }
@@ -0,0 +1,6 @@
1
+ import type { ButtonContent, BrandPageModel } from '../../../brand-page/models';
2
+ import type { BuilderResult } from '../../models';
3
+ import { BaseSectionBuilder } from './base-section-builder';
4
+ export declare class ButtonSectionBuilder extends BaseSectionBuilder<ButtonContent> {
5
+ buildAsync(model: BrandPageModel): Promise<BuilderResult>;
6
+ }
@@ -0,0 +1,16 @@
1
+ import { applyScalarFields } from '../section-field-utils';
2
+ import { BaseSectionBuilder } from './base-section-builder';
3
+ export class ButtonSectionBuilder extends BaseSectionBuilder {
4
+ async buildAsync(model) {
5
+ this.log('Build called');
6
+ const validation = await this.validateAsync();
7
+ if (validation.errors.length) {
8
+ return { request: this.request, model, errors: validation.errors };
9
+ }
10
+ const resolved = this.resolveContent(model);
11
+ if ('error' in resolved)
12
+ return resolved.error;
13
+ applyScalarFields(resolved.content, this.args, this.sectionType);
14
+ return { request: this.request, model };
15
+ }
16
+ }
@@ -0,0 +1,6 @@
1
+ import type { ContactFormContent, BrandPageModel } from '../../../brand-page/models';
2
+ import type { BuilderResult } from '../../models';
3
+ import { BaseSectionBuilder } from './base-section-builder';
4
+ export declare class ContactFormBuilder extends BaseSectionBuilder<ContactFormContent> {
5
+ buildAsync(model: BrandPageModel): Promise<BuilderResult>;
6
+ }
@@ -0,0 +1,27 @@
1
+ import { applyScalarFields, applyStyleFields } from '../section-field-utils';
2
+ import { BaseSectionBuilder } from './base-section-builder';
3
+ export class ContactFormBuilder extends BaseSectionBuilder {
4
+ async buildAsync(model) {
5
+ this.log('Build called');
6
+ const validation = await this.validateAsync();
7
+ if (validation.errors.length) {
8
+ return { request: this.request, model, errors: validation.errors };
9
+ }
10
+ const resolved = this.resolveContent(model);
11
+ if ('error' in resolved)
12
+ return resolved.error;
13
+ const content = resolved.content;
14
+ applyScalarFields(content, this.args, this.sectionType);
15
+ applyStyleFields(content, this.args, this.sectionType);
16
+ const args = this.args;
17
+ if (args.fields && Array.isArray(args.fields) && content.fields) {
18
+ for (const toggle of args.fields) {
19
+ const field = content.fields.find((f) => f.id === toggle.field_id);
20
+ if (field) {
21
+ field.enabled = toggle.enabled;
22
+ }
23
+ }
24
+ }
25
+ return { request: this.request, model };
26
+ }
27
+ }
@@ -0,0 +1,13 @@
1
+ import type { BrandPageModel } from '../../../brand-page/models';
2
+ import { BaseMetadataBuilder, type BuilderResult, type MetadataBuilderRequest } from '../../models';
3
+ import type { Logger } from '../../logger';
4
+ export interface DeleteSectionPayload {
5
+ contentId: string;
6
+ }
7
+ export declare class DeleteSectionBuilder extends BaseMetadataBuilder<DeleteSectionPayload> {
8
+ constructor(request: MetadataBuilderRequest<DeleteSectionPayload>, logger?: Logger);
9
+ validateAsync(): Promise<{
10
+ errors: string[];
11
+ }>;
12
+ buildAsync(model: BrandPageModel): Promise<BuilderResult>;
13
+ }
@@ -0,0 +1,37 @@
1
+ import { BaseMetadataBuilder, } from '../../models';
2
+ export class DeleteSectionBuilder extends BaseMetadataBuilder {
3
+ constructor(request, logger) {
4
+ super(request, logger);
5
+ }
6
+ async validateAsync() {
7
+ const errors = [];
8
+ const payload = this.request.payload;
9
+ if (!payload?.contentId) {
10
+ errors.push('contentId is required for delete_section');
11
+ }
12
+ return { errors };
13
+ }
14
+ async buildAsync(model) {
15
+ this.log('Build called');
16
+ const validation = await this.validateAsync();
17
+ if (validation.errors.length) {
18
+ return { request: this.request, model, errors: validation.errors };
19
+ }
20
+ const { contentId } = this.request.payload;
21
+ for (const page of model.pages) {
22
+ const index = page.contents.findIndex((c) => c.id === contentId);
23
+ if (index !== -1) {
24
+ page.contents.splice(index, 1);
25
+ this.log({
26
+ message: `Deleted section ${contentId} from page ${page.id}`,
27
+ });
28
+ return { request: this.request, model };
29
+ }
30
+ }
31
+ return {
32
+ request: this.request,
33
+ model,
34
+ errors: [`Section with ID "${contentId}" not found`],
35
+ };
36
+ }
37
+ }
@@ -0,0 +1,6 @@
1
+ import type { DividerSectionContent, BrandPageModel } from '../../../brand-page/models';
2
+ import type { BuilderResult } from '../../models';
3
+ import { BaseSectionBuilder } from './base-section-builder';
4
+ export declare class DividerSectionBuilder extends BaseSectionBuilder<DividerSectionContent> {
5
+ buildAsync(model: BrandPageModel): Promise<BuilderResult>;
6
+ }
@@ -0,0 +1,16 @@
1
+ import { applyScalarFields } from '../section-field-utils';
2
+ import { BaseSectionBuilder } from './base-section-builder';
3
+ export class DividerSectionBuilder extends BaseSectionBuilder {
4
+ async buildAsync(model) {
5
+ this.log('Build called');
6
+ const validation = await this.validateAsync();
7
+ if (validation.errors.length) {
8
+ return { request: this.request, model, errors: validation.errors };
9
+ }
10
+ const resolved = this.resolveContent(model);
11
+ if ('error' in resolved)
12
+ return resolved.error;
13
+ applyScalarFields(resolved.content, this.args, this.sectionType);
14
+ return { request: this.request, model };
15
+ }
16
+ }
@@ -0,0 +1,6 @@
1
+ import type { ImageGalleryContent, BrandPageModel } from '../../../brand-page/models';
2
+ import type { BuilderResult } from '../../models';
3
+ import { BaseSectionBuilder } from './base-section-builder';
4
+ export declare class ImageGalleryBuilder extends BaseSectionBuilder<ImageGalleryContent> {
5
+ buildAsync(model: BrandPageModel): Promise<BuilderResult>;
6
+ }