@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
@@ -5,6 +5,8 @@ export interface SnapshotState {
5
5
  isCapturing: boolean;
6
6
  }
7
7
 
8
+ let captureCallback: (() => Promise<void>) | null = null;
9
+
8
10
  export const useSnapshotStore = defineStore('snapshot', {
9
11
  state: (): SnapshotState => ({
10
12
  snapshotBase64: null,
@@ -23,6 +25,16 @@ export const useSnapshotStore = defineStore('snapshot', {
23
25
  clearSnapshot() {
24
26
  this.snapshotBase64 = null;
25
27
  },
28
+
29
+ registerCaptureCallback(callback: () => Promise<void>) {
30
+ captureCallback = callback;
31
+ },
32
+
33
+ async refreshSnapshotAsync() {
34
+ if (captureCallback) {
35
+ await captureCallback();
36
+ }
37
+ },
26
38
  },
27
39
 
28
40
  getters: {
@@ -1,9 +1,11 @@
1
1
  import axios, { type AxiosError } from 'axios';
2
- import { useBrandPageContainerStore } from '@brand-page-maker/stores/brandpage-container/brand-page-container-store';
2
+ import { useBrandPageContainerStore } from '../brand-page-maker/stores/brandpage-container/brand-page-container-store';
3
+ import type { MinifiedBrandPageMetadata } from '../utils/minify-brand-page-metadata';
3
4
 
4
5
  // Agent types
5
6
  export const AI_ASSISTANT_AGENT_TYPES = {
6
7
  WEBSITE_TEXT_ELEMENT: 'website_text_element',
8
+ WEBSITE_BUILDER: 'website_builder',
7
9
  } as const;
8
10
 
9
11
  export type AiAssistantAgentType =
@@ -258,6 +260,20 @@ export const buildWebsiteTextElementMessage = (
258
260
  return JSON.stringify(content);
259
261
  };
260
262
 
263
+ /**
264
+ * Build the message content for website builder agent.
265
+ * Embeds minified metadata as a JSON code fence in the message text
266
+ * so the ai-pipeline's _extract_context_from_request() can parse it.
267
+ */
268
+ export const buildWebsiteBuilderMessage = (
269
+ userPrompt: string,
270
+ minifiedMetadata: MinifiedBrandPageMetadata,
271
+ ): string => {
272
+ const metadataJson = JSON.stringify(minifiedMetadata);
273
+
274
+ return `${userPrompt}\n\nmetadata:\n\`\`\`json\n${metadataJson}\n\`\`\``;
275
+ };
276
+
261
277
  let _instance: AiAssistantClient | undefined;
262
278
 
263
279
  export const getInstance = (): AiAssistantClient =>
@@ -67,12 +67,59 @@ export function useSnapshot() {
67
67
  throw new Error('html2canvas failed to load');
68
68
  }
69
69
 
70
+ // Pre-fetch blob URLs from shape <object> elements so they can be
71
+ // rendered as <img> in the html2canvas clone (html2canvas cannot
72
+ // traverse the isolated DOM inside <object> elements).
73
+ const shapeDataUris = new Map<string, string>();
74
+ const shapeObjects = element.querySelectorAll('.c-shape-object object');
75
+
76
+ for (const obj of Array.from(shapeObjects)) {
77
+ const dataUrl = obj.getAttribute('data');
78
+
79
+ if (dataUrl && dataUrl.startsWith('blob:')) {
80
+ try {
81
+ const response = await fetch(dataUrl);
82
+ const svgText = await response.text();
83
+
84
+ shapeDataUris.set(
85
+ dataUrl,
86
+ `data:image/svg+xml,${encodeURIComponent(svgText)}`,
87
+ );
88
+ } catch {
89
+ /* skip – shape will render as blank, same as before */
90
+ }
91
+ }
92
+ }
93
+
70
94
  const canvas = await window.html2canvas(element, {
71
95
  allowTaint: true,
72
96
  useCORS: true,
73
97
  scale: 0.8, // Reduce quality to decrease file size
74
98
  logging: false,
75
99
  backgroundColor: '#ffffff',
100
+ onclone: (_doc: Document, clonedElement: HTMLElement) => {
101
+ const clonedObjects = clonedElement.querySelectorAll(
102
+ '.c-shape-object object',
103
+ );
104
+
105
+ clonedObjects.forEach((obj) => {
106
+ const dataUrl = obj.getAttribute('data');
107
+
108
+ if (dataUrl && shapeDataUris.has(dataUrl)) {
109
+ const img = _doc.createElement('img');
110
+
111
+ img.src = shapeDataUris.get(dataUrl)!;
112
+
113
+ const style = (obj as HTMLElement).getAttribute('style');
114
+
115
+ if (style) {
116
+ img.setAttribute('style', style);
117
+ }
118
+
119
+ obj.parentNode?.replaceChild(img, obj);
120
+ }
121
+ });
122
+ },
76
123
  });
77
124
 
78
125
  const base64Image = canvas.toDataURL('image/jpeg', 0.8); // Use JPEG with 80% quality for smaller size
package/src/lib.ts CHANGED
@@ -60,6 +60,10 @@ export {
60
60
  getBrandPageViewModelFromBrandPageModel,
61
61
  migrateBrandPageModel,
62
62
  } from './brand-page/utils';
63
+ export {
64
+ minifyBrandPageMetadata,
65
+ type MinifiedBrandPageMetadata,
66
+ } from './utils/minify-brand-page-metadata';
63
67
  export * as brandPageUtils from './brand-page/utils';
64
68
  export type { CriticalResourceURLs } from './brand-page/utils/view-model.util';
65
69
  export {
@@ -6,15 +6,23 @@ import { MetadataExecutor } from './metadata-executor';
6
6
  import {
7
7
  type MetadataBuilderRequest,
8
8
  type MetadataExecutorResult,
9
+ type BuilderType,
10
+ BUILDER_TYPES,
9
11
  } from './models';
10
12
  import {
11
13
  AI_ASSISTANT_TOOL_NAMES,
14
+ SECTION_TOOL_MAP,
12
15
  type ParsedToolCall,
13
16
  type UpdateStyleToolArguments,
14
17
  type UpdateTextToolArguments,
18
+ type DeleteSectionArguments,
19
+ type MoveSectionArguments,
20
+ type AddPageArguments,
21
+ type RemovePageArguments,
15
22
  } from './parsers/ai-toolcall-parser';
23
+ import type { SectionToolCallShape } from './parsers/section-tool-arguments';
16
24
 
17
- export const executeAiToolUseAsync = async (
25
+ export const executeToolCallsAsync = async (
18
26
  metadata: BrandPageModel,
19
27
  toolcalls: ParsedToolCall[],
20
28
  options: {
@@ -22,36 +30,118 @@ export const executeAiToolUseAsync = async (
22
30
  maxCharacters?: number;
23
31
  },
24
32
  ): Promise<MetadataExecutorResult> => {
25
- const requests: MetadataBuilderRequest[] = toolcalls.map((toolcall) => {
26
- switch (toolcall.function) {
27
- case AI_ASSISTANT_TOOL_NAMES.UPDATE_TEXT: {
28
- const arg = toolcall.arguments as UpdateTextToolArguments;
29
-
30
- return buildUpdateTextRequest(toolcall.toolId, {
31
- contentId: arg.contentId,
32
- fieldName: arg.fieldName,
33
- newText: arg.metadata.text,
34
- maxCharacters: options.maxCharacters,
35
- });
36
- }
33
+ const requests: MetadataBuilderRequest[] = toolcalls
34
+ .map((toolcall): MetadataBuilderRequest | null => {
35
+ switch (toolcall.function) {
36
+ case AI_ASSISTANT_TOOL_NAMES.UPDATE_TEXT: {
37
+ const arg = toolcall.arguments as unknown as UpdateTextToolArguments;
37
38
 
38
- case AI_ASSISTANT_TOOL_NAMES.UPDATE_STYLE: {
39
- const arg = toolcall.arguments as UpdateStyleToolArguments;
39
+ return buildUpdateTextRequest(toolcall.toolId, {
40
+ contentId: arg.contentId,
41
+ fieldName: arg.fieldName,
42
+ newText: arg.metadata.text,
43
+ maxCharacters: options.maxCharacters,
44
+ });
45
+ }
40
46
 
41
- return buildUpdateTextStyleRequest(toolcall.toolId, {
42
- contentId: arg.contentId,
43
- fieldName: arg.fieldName,
44
- newStyles: arg.metadata.style,
45
- });
46
- }
47
+ case AI_ASSISTANT_TOOL_NAMES.UPDATE_STYLE: {
48
+ const arg = toolcall.arguments as unknown as UpdateStyleToolArguments;
49
+
50
+ return buildUpdateTextStyleRequest(toolcall.toolId, {
51
+ contentId: arg.contentId,
52
+ fieldName: arg.fieldName,
53
+ newStyles: arg.metadata.style,
54
+ });
55
+ }
56
+
57
+ case AI_ASSISTANT_TOOL_NAMES.DELETE_SECTION: {
58
+ const arg = toolcall.arguments as unknown as DeleteSectionArguments;
59
+
60
+ return {
61
+ id: toolcall.toolId,
62
+ type: BUILDER_TYPES.DELETE_SECTION as BuilderType,
63
+ payload: {
64
+ contentId: arg.content_id,
65
+ },
66
+ };
67
+ }
68
+
69
+ case AI_ASSISTANT_TOOL_NAMES.MOVE_SECTION: {
70
+ const arg = toolcall.arguments as unknown as MoveSectionArguments;
71
+
72
+ return {
73
+ id: toolcall.toolId,
74
+ type: BUILDER_TYPES.MOVE_SECTION as BuilderType,
75
+ payload: {
76
+ contentId: arg.content_id,
77
+ position: arg.position,
78
+ targetPageId: arg.target_page_id,
79
+ },
80
+ };
81
+ }
82
+
83
+ case AI_ASSISTANT_TOOL_NAMES.ADD_PAGE: {
84
+ const arg = toolcall.arguments as unknown as AddPageArguments;
85
+
86
+ return {
87
+ id: toolcall.toolId,
88
+ type: BUILDER_TYPES.ADD_PAGE as BuilderType,
89
+ payload: {
90
+ pageId: arg.page_id,
91
+ pageName: arg.page_name,
92
+ },
93
+ };
94
+ }
95
+
96
+ case AI_ASSISTANT_TOOL_NAMES.REMOVE_PAGE: {
97
+ const arg = toolcall.arguments as unknown as RemovePageArguments;
98
+
99
+ return {
100
+ id: toolcall.toolId,
101
+ type: BUILDER_TYPES.REMOVE_PAGE as BuilderType,
102
+ payload: {
103
+ pageId: arg.page_id,
104
+ },
105
+ };
106
+ }
107
+
108
+ default: {
109
+ const sectionTool = SECTION_TOOL_MAP[toolcall.function];
110
+
111
+ if (!sectionTool) {
112
+ console.warn(
113
+ `[executeToolCallsAsync] Skipping unsupported tool call: ${toolcall.function}`,
114
+ );
115
+
116
+ return null;
117
+ }
118
+
119
+ const {
120
+ mode,
121
+ content_id: contentId,
122
+ page_id: pageId,
123
+ arguments: sectionArgs,
124
+ } = toolcall.arguments as unknown as SectionToolCallShape;
125
+
126
+ const builderType =
127
+ `${mode}-${sectionTool.sectionType}` as BuilderType;
47
128
 
48
- default: {
49
- throw new Error(`Unsupported tool call: ${toolcall.function}`);
129
+ return {
130
+ id: toolcall.toolId,
131
+ type: builderType,
132
+ payload: {
133
+ sectionType: sectionTool.sectionType,
134
+ contentId: contentId as string,
135
+ arguments: sectionArgs,
136
+ pageId: pageId as string,
137
+ },
138
+ };
139
+ }
50
140
  }
51
- }
52
- });
141
+ })
142
+ .filter((r): r is MetadataBuilderRequest => r !== null);
53
143
 
54
- options.logger?.log('executeAiToolUseAsync', { requests });
144
+ options.logger?.log('executeToolCallsAsync', { requests });
55
145
 
56
146
  const executor = new MetadataExecutor();
57
147
 
@@ -0,0 +1,98 @@
1
+ import { PageModel, type BrandPageModel } from '../../brand-page/models';
2
+ import { getPageSlugFromPageTitle } from '../../brand-page-maker/utils/slug.util';
3
+ import {
4
+ BaseMetadataBuilder,
5
+ type BuilderResult,
6
+ type MetadataBuilderRequest,
7
+ } from '../models';
8
+ import type { Logger } from '../logger';
9
+
10
+ export interface AddPagePayload {
11
+ pageId: string;
12
+ pageName: string;
13
+ }
14
+
15
+ export class AddPageBuilder extends BaseMetadataBuilder<AddPagePayload> {
16
+ constructor(
17
+ request: MetadataBuilderRequest<AddPagePayload>,
18
+ logger?: Logger,
19
+ ) {
20
+ super(request, logger);
21
+ }
22
+
23
+ async validateAsync(): Promise<{ errors: string[] }> {
24
+ const errors: string[] = [];
25
+ const payload = this.request.payload;
26
+
27
+ if (!payload?.pageId) {
28
+ errors.push('page_id is required for add_page');
29
+ }
30
+
31
+ if (!payload?.pageName) {
32
+ errors.push('page_name is required for add_page');
33
+ }
34
+
35
+ return { errors };
36
+ }
37
+
38
+ async buildAsync(model: BrandPageModel): Promise<BuilderResult> {
39
+ this.log('Build called');
40
+
41
+ const validation = await this.validateAsync();
42
+
43
+ if (validation.errors.length) {
44
+ return { request: this.request, model, errors: validation.errors };
45
+ }
46
+
47
+ const { pageId, pageName } = this.request.payload!;
48
+
49
+ // Check if page with this ID already exists
50
+ if (model.pages.some((p) => p.id === pageId)) {
51
+ return {
52
+ request: this.request,
53
+ model,
54
+ errors: [`Page with ID "${pageId}" already exists`],
55
+ };
56
+ }
57
+
58
+ // Create the new page
59
+ const newPage = new PageModel({
60
+ id: pageId,
61
+ title: pageName,
62
+ contents: [],
63
+ isHidden: false,
64
+ });
65
+
66
+ // Insert the new page before any hidden pages
67
+ const visiblePages = model.pages.filter((page) => !page.isHidden);
68
+ const hiddenPages = model.pages.filter((page) => page.isHidden);
69
+
70
+ model.pages = [...visiblePages, newPage, ...hiddenPages];
71
+
72
+ // Construct slug from page name, ensuring uniqueness against existing routes
73
+ const existingSlugs = model.nav.routes.map((r) => r.pageSlug);
74
+ const slug = getPageSlugFromPageTitle(pageName, existingSlugs);
75
+
76
+ // Add nav route and order entry
77
+ const routeId = `route-${pageId}`;
78
+
79
+ model.nav.routes.push({
80
+ id: routeId,
81
+ pageId,
82
+ pageSlug: slug,
83
+ isHidden: false,
84
+ displayName: pageName,
85
+ });
86
+
87
+ model.nav.orders.push({
88
+ routeId,
89
+ subRoutes: [],
90
+ });
91
+
92
+ this.log({
93
+ message: `Added page "${pageName}" (${pageId}) with slug "/${slug}"`,
94
+ });
95
+
96
+ return { request: this.request, model };
97
+ }
98
+ }
@@ -0,0 +1,83 @@
1
+ import { type BrandPageModel } from '../../brand-page/models';
2
+ import {
3
+ BaseMetadataBuilder,
4
+ type BuilderResult,
5
+ type MetadataBuilderRequest,
6
+ } from '../models';
7
+ import type { Logger } from '../logger';
8
+
9
+ export interface RemovePagePayload {
10
+ pageId: string;
11
+ }
12
+
13
+ export class RemovePageBuilder extends BaseMetadataBuilder<RemovePagePayload> {
14
+ constructor(
15
+ request: MetadataBuilderRequest<RemovePagePayload>,
16
+ logger?: Logger,
17
+ ) {
18
+ super(request, logger);
19
+ }
20
+
21
+ async validateAsync(): Promise<{ errors: string[] }> {
22
+ const errors: string[] = [];
23
+ const payload = this.request.payload;
24
+
25
+ if (!payload?.pageId) {
26
+ errors.push('page_id is required for remove_page');
27
+ }
28
+
29
+ return { errors };
30
+ }
31
+
32
+ async buildAsync(model: BrandPageModel): Promise<BuilderResult> {
33
+ this.log('Build called');
34
+
35
+ const validation = await this.validateAsync();
36
+
37
+ if (validation.errors.length) {
38
+ return { request: this.request, model, errors: validation.errors };
39
+ }
40
+
41
+ const { pageId } = this.request.payload!;
42
+
43
+ // Check if page exists
44
+ const pageIndex = model.pages.findIndex((p) => p.id === pageId);
45
+
46
+ if (pageIndex === -1) {
47
+ return {
48
+ request: this.request,
49
+ model,
50
+ errors: [`Page with ID "${pageId}" not found`],
51
+ };
52
+ }
53
+
54
+ const page = model.pages[pageIndex];
55
+
56
+ // Remove the page
57
+ model.pages.splice(pageIndex, 1);
58
+
59
+ // Remove matching nav route(s)
60
+ const removedRouteIds = new Set<string>();
61
+
62
+ model.nav.routes = model.nav.routes.filter((route) => {
63
+ if (route.pageId === pageId) {
64
+ removedRouteIds.add(route.id);
65
+
66
+ return false;
67
+ }
68
+
69
+ return true;
70
+ });
71
+
72
+ // Remove matching nav order entries
73
+ model.nav.orders = model.nav.orders.filter(
74
+ (order) => !removedRouteIds.has(order.routeId),
75
+ );
76
+
77
+ this.log({
78
+ message: `Removed page "${page.title}" (${pageId})`,
79
+ });
80
+
81
+ return { request: this.request, model };
82
+ }
83
+ }
@@ -0,0 +1,28 @@
1
+ import type {
2
+ AboutSectionContent,
3
+ BrandPageModel,
4
+ } from '../../../brand-page/models';
5
+ import type { BuilderResult } from '../../models';
6
+ import { applyScalarFields, applyStyleFields } from '../section-field-utils';
7
+ import { BaseSectionBuilder } from './base-section-builder';
8
+
9
+ export class AboutSectionBuilder extends BaseSectionBuilder<AboutSectionContent> {
10
+ async buildAsync(model: BrandPageModel): Promise<BuilderResult> {
11
+ this.log('Build called');
12
+
13
+ const validation = await this.validateAsync();
14
+
15
+ if (validation.errors.length) {
16
+ return { request: this.request, model, errors: validation.errors };
17
+ }
18
+
19
+ const resolved = this.resolveContent(model);
20
+
21
+ if ('error' in resolved) return resolved.error;
22
+
23
+ applyScalarFields(resolved.content, this.args, this.sectionType);
24
+ applyStyleFields(resolved.content, this.args, this.sectionType);
25
+
26
+ return { request: this.request, model };
27
+ }
28
+ }
@@ -0,0 +1,45 @@
1
+ import type {
2
+ BannerSectionContent,
3
+ BrandPageModel,
4
+ } from '../../../brand-page/models';
5
+ import type { BuilderResult } from '../../models';
6
+ import type { BannerSectionArguments } from '../../parsers/section-tool-arguments';
7
+ import {
8
+ applyScalarFields,
9
+ applyStyleFields,
10
+ applyRTEStyles,
11
+ } from '../section-field-utils';
12
+ import { BaseSectionBuilder } from './base-section-builder';
13
+
14
+ const applyBackgroundImage = (
15
+ content: BannerSectionContent,
16
+ args: BannerSectionArguments,
17
+ ): void => {
18
+ if (args.background_image_url) {
19
+ content.media = undefined;
20
+ content.mediaType = 'image';
21
+ }
22
+ };
23
+
24
+ export class BannerSectionBuilder extends BaseSectionBuilder<BannerSectionContent> {
25
+ async buildAsync(model: BrandPageModel): Promise<BuilderResult> {
26
+ this.log('Build called');
27
+
28
+ const validation = await this.validateAsync();
29
+
30
+ if (validation.errors.length) {
31
+ return { request: this.request, model, errors: validation.errors };
32
+ }
33
+
34
+ const resolved = this.resolveContent(model);
35
+
36
+ if ('error' in resolved) return resolved.error;
37
+
38
+ applyScalarFields(resolved.content, this.args, this.sectionType);
39
+ applyStyleFields(resolved.content, this.args, this.sectionType);
40
+ applyRTEStyles(resolved.content, this.args, this.sectionType);
41
+ applyBackgroundImage(resolved.content, this.args as BannerSectionArguments);
42
+
43
+ return { request: this.request, model };
44
+ }
45
+ }