@designcrowd/library.brand-page 6.0.5 → 6.0.6-ast-bugs

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 (395) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-DhzvKlTS.js → CreatedOnBrandCrowd-de-de-SHCspMwS.js} +3 -3
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-DKH4lmNV.js → CreatedOnBrandCrowd-en-us-C6lITAAT.js} +3 -3
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-RloPCLuV.js → CreatedOnBrandCrowd-es-es-Uh69c4vZ.js} +3 -3
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-Cu9e2H0K.js → CreatedOnBrandCrowd-fr-ca-Bb0rp7BV.js} +3 -3
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-Cu9e2H0K.js → CreatedOnBrandCrowd-fr-fr-Bb0rp7BV.js} +3 -3
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-CiCnjxBZ.js → CreatedOnBrandCrowd-pt-br-DsrQHcjs.js} +3 -3
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-CiCnjxBZ.js → CreatedOnBrandCrowd-pt-pt-DsrQHcjs.js} +3 -3
  8. package/lib/src/{CreatedOnDcom-de-de-CwlnedFV.js → CreatedOnDcom-de-de-BshZYzSp.js} +3 -3
  9. package/lib/src/{CreatedOnDcom-en-us-DFHex61v.js → CreatedOnDcom-en-us-CLu8mKUW.js} +3 -3
  10. package/lib/src/{CreatedOnDcom-es-es-BTxH6I4V.js → CreatedOnDcom-es-es-BZYhkONd.js} +3 -3
  11. package/lib/src/{CreatedOnDcom-fr-ca-BVw0KYxu.js → CreatedOnDcom-fr-ca-CIaBEp_9.js} +3 -3
  12. package/lib/src/{CreatedOnDcom-fr-fr-DaqNz1Er.js → CreatedOnDcom-fr-fr-dyF7hioJ.js} +3 -3
  13. package/lib/src/{CreatedOnDcom-pt-br-B4KsMI8W.js → CreatedOnDcom-pt-br-CUHjk2du.js} +3 -3
  14. package/lib/src/{CreatedOnDcom-pt-pt-CWoHEtOZ.js → CreatedOnDcom-pt-pt-CWDvQidv.js} +3 -3
  15. package/lib/src/brand-page/clients/brand-page.client.d.ts +9 -9
  16. package/lib/src/brand-page/components/banner-section/BannerSection.mixin.d.ts +103 -0
  17. package/lib/src/brand-page/components/banner-section/BannerSection.mixin.js +178 -0
  18. package/lib/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.d.ts +1 -2
  19. package/lib/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.d.ts +4 -2
  20. package/lib/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.js +1 -0
  21. package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.d.ts +4 -2
  22. package/lib/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.js +11 -5
  23. package/lib/src/brand-page/components/page/Page.mixin.d.ts +1 -1
  24. package/lib/src/brand-page/components/page/PageComponent.mixin.d.ts +1 -1
  25. package/lib/src/brand-page/components/payment/Payment.mixin.d.ts +3 -3
  26. package/lib/src/brand-page/components/payment/__fixtures__/request-payment.d.ts +13 -13
  27. package/lib/src/brand-page/components/payment/__fixtures__/support-me.d.ts +13 -13
  28. package/lib/src/brand-page/constants/sections/footer-display.constants.js +1 -1
  29. package/lib/src/brand-page/models/index.d.ts +2 -13
  30. package/lib/src/brand-page/models/index.js +3 -0
  31. package/lib/src/brand-page/models/payment.model.d.ts +1 -1
  32. package/lib/src/brand-page/utils/personalisation.util.js +72 -14
  33. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +21 -19
  34. package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.js +1 -0
  35. package/lib/src/brand-page-maker/components/admin-background-settings/AdminBackgroundSettings.mixin.d.ts +16 -10
  36. package/lib/src/brand-page-maker/components/admin-background-settings/ShapePositionSlider.mixin.d.ts +1 -1
  37. package/lib/src/brand-page-maker/components/admin-logo-settings/AdminLogoSettings.mixin.d.ts +3 -3
  38. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +181 -170
  39. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +3 -0
  40. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.js +1 -0
  41. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +12 -12
  42. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.stories.js +2 -2
  43. package/lib/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-payment.js +0 -7
  44. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +148 -149
  45. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +21 -21
  46. package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.js +1 -1
  47. package/lib/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.d.ts +4 -2
  48. package/lib/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.js +1 -0
  49. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.d.ts +4 -2
  50. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.js +1 -0
  51. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.d.ts +5 -2
  52. package/lib/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.js +1 -0
  53. package/lib/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.d.ts +4 -2
  54. package/lib/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.js +1 -0
  55. package/lib/src/brand-page-maker/components/device/Device.mixin.d.ts +4 -2
  56. package/lib/src/brand-page-maker/components/device/Device.mixin.js +1 -0
  57. package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.d.ts +4 -2
  58. package/lib/src/brand-page-maker/components/navigation/Navigation.mixin.js +1 -0
  59. package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +3 -3
  60. package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +11 -11
  61. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +27 -25
  62. package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.js +1 -0
  63. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +27 -27
  64. package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.js +1 -1
  65. package/lib/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.mixin.d.ts +17 -12
  66. package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +12 -12
  67. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +30 -32
  68. package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.js +16 -5
  69. package/lib/src/brand-page-maker/components/upgrade-to-premium-button/UpgradeToPremiumButton.mixin.d.ts +11 -11
  70. package/lib/src/brand-page-maker/composables/ai-chat/types.d.ts +3 -0
  71. package/lib/src/brand-page-maker/composables/ai-chat/ui-actions.d.ts +29 -0
  72. package/lib/src/brand-page-maker/composables/ai-chat/ui-actions.js +32 -0
  73. package/lib/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.js +204 -177
  74. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +1 -1
  75. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +6 -6
  76. package/lib/src/brand-page-maker/composables/useEventTracker.d.ts +3 -2
  77. package/lib/src/brand-page-maker/composables/useEventTracker.js +1 -0
  78. package/lib/src/brand-page-maker/constants/config-settings-constant.d.ts +6 -6
  79. package/lib/src/brand-page-maker/constants/config-settings-constant.js +3 -3
  80. package/lib/src/brand-page-maker/convertors/text-image-display-style.convertor.d.ts +1 -1
  81. package/lib/src/brand-page-maker/convertors/text-image-display-style.convertor.js +1 -1
  82. package/lib/src/brand-page-maker/models/content-settings.d.ts +1 -1
  83. package/lib/src/brand-page-maker/models/navigation-style-configs.js +1 -1
  84. package/lib/src/brand-page-maker/routing/brand-page-maker-router.d.ts +1 -2
  85. package/lib/src/brand-page-maker/stores/ai-checkpoint/ai-checkpoint-store.d.ts +366 -378
  86. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.d.ts +5 -4
  87. package/lib/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.js +8 -5
  88. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +3 -1
  89. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +7 -3
  90. package/lib/src/brand-page-maker/stores/history/history-store.d.ts +15 -15
  91. package/lib/src/brand-page-maker/stores/ui/ui-store.d.ts +6 -0
  92. package/lib/src/brand-page-maker/stores/ui/ui-store.js +8 -0
  93. package/lib/src/brand-page-maker/utils/content-settings.util.js +1 -1
  94. package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +1 -1
  95. package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +4 -4
  96. package/lib/src/clients/ai-assistant-client.d.ts +7 -0
  97. package/lib/src/clients/brand-page-client.d.ts +16 -15
  98. package/lib/src/clients/design-template-client.d.ts +3 -0
  99. package/lib/src/clients/media-client.d.ts +2 -2
  100. package/lib/src/clients/models.d.ts +2 -0
  101. package/lib/src/composables/useSnapshot.js +18 -18
  102. package/lib/src/css/library.brand-page-brandCrowd.min.css +371 -344
  103. package/lib/src/css/library.brand-page-brandPage.min.css +649 -344
  104. package/lib/src/css/library.brand-page-designCom.min.css +371 -344
  105. package/lib/src/css/library.brand-page-preview.min.css +627 -344
  106. package/lib/src/index.d.ts +4 -0
  107. package/lib/src/index.mjs +107 -104
  108. package/lib/src/{lib-BPI8E2Ui.js → lib-COw-Rz05.js} +37005 -33761
  109. package/lib/src/lib.js +10 -0
  110. package/lib/src/metadata-builder/builders/footer-builder.js +105 -62
  111. package/lib/src/metadata-builder/builders/section-builders/image-gallery-builder.js +68 -57
  112. package/lib/src/metadata-builder/builders/section-builders/images-section-builder.js +93 -58
  113. package/lib/src/metadata-builder/builders/section-builders/shapes-section-builder.js +99 -66
  114. package/lib/src/metadata-builder/builders/section-builders/social-links-builder.js +17 -57
  115. package/lib/src/metadata-builder/builders/section-builders/testimonial-section-builder.js +85 -51
  116. package/lib/src/metadata-builder/builders/section-builders/text-section-builder.js +74 -49
  117. package/lib/src/metadata-builder/builders/section-field-utils.d.ts +7 -0
  118. package/lib/src/metadata-builder/builders/section-field-utils.js +1 -1
  119. package/lib/src/metadata-builder/builders/shape-color-utils.js +1 -1
  120. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +7 -16
  121. package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +48 -66
  122. package/lib/src/plugins/google-maps-plugin/google-maps-plugin.d.ts +1 -1
  123. package/lib/src/plugins/google-maps-plugin/google-maps-plugin.js +8 -8
  124. package/lib/src/shared/background-settings/components/background-shapes/BackgroundShapeSettings.mixin.d.ts +13 -13
  125. package/lib/src/shared/background-settings/store/background-settings-store.d.ts +3 -3
  126. package/lib/src/shared/color-picker/components/ColorPicker.mixin.d.ts +4 -2
  127. package/lib/src/shared/color-picker/components/ColorPicker.mixin.js +2 -2
  128. package/lib/src/shared/color-picker/components/ColorPickerSwatch.mixin.d.ts +4 -2
  129. package/lib/src/shared/color-picker/components/ColorPickerSwatch.mixin.js +1 -0
  130. package/lib/src/shared/confirm-modal/ConfirmModal.mixin.d.ts +5 -2
  131. package/lib/src/shared/confirm-modal/ConfirmModal.mixin.js +1 -0
  132. package/lib/src/shared/content-settings/components/GenericTextInput.mixin.d.ts +0 -1
  133. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +131 -129
  134. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.js +2 -1
  135. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +111 -110
  136. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +84 -81
  137. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.js +5 -0
  138. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +117 -109
  139. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.js +1 -14
  140. package/lib/src/shared/content-settings/components/email-field/EmailField.mixin.d.ts +0 -1
  141. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +72 -70
  142. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.js +4 -3
  143. package/lib/src/shared/content-settings/components/form-fields-field/FormFieldsField.mixin.d.ts +4 -4
  144. package/lib/src/shared/content-settings/components/icon-library/IconLibrary.mixin.d.ts +3 -1
  145. package/lib/src/shared/content-settings/components/icon-library/IconLibrary.mixin.js +1 -0
  146. package/lib/src/shared/content-settings/components/images-field/ImagesField.mixin.d.ts +2 -2
  147. package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.d.ts +4 -3
  148. package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.js +1 -1
  149. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +40 -40
  150. package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigOptionField.mixin.d.ts +5 -6
  151. package/lib/src/shared/content-settings/components/shape-field/ShapeField.mixin.d.ts +0 -1
  152. package/lib/src/shared/content-settings/components/slider-field/SliderField.mixin.d.ts +2 -2
  153. package/lib/src/shared/content-settings/components/tel-field/TelField.mixin.d.ts +0 -1
  154. package/lib/src/shared/content-settings/components/testimonial-items-field/TestimonialItemsField.mixin.d.ts +1 -2
  155. package/lib/src/shared/content-settings/components/text-field/TextField.mixin.d.ts +0 -1
  156. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.d.ts +1 -2
  157. package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.js +1 -1
  158. package/lib/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.d.ts +28 -28
  159. package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +0 -1
  160. package/lib/src/shared/content-settings/components/toggle-field/ToggleField.mixin.d.ts +2 -2
  161. package/lib/src/shared/content-settings/components/url-field/UrlField.mixin.d.ts +0 -1
  162. package/lib/src/shared/content-settings/components/youtube-video-field/YoutubeVideoField.mixin.d.ts +0 -1
  163. package/lib/src/shared/content-settings/store/content-settings-store.d.ts +39 -39
  164. package/lib/src/shared/content-settings/utils.js +0 -1
  165. package/lib/src/shared/font-family-selector/FontFamilySelector.mixin.d.ts +6 -4
  166. package/lib/src/shared/font-family-selector/FontFamilySelector.mixin.js +1 -0
  167. package/lib/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.d.ts +4 -2
  168. package/lib/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.js +1 -0
  169. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.d.ts +29 -21
  170. package/lib/src/shared/logo-settings/components/EditLogoSettings.mixin.js +1 -1
  171. package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +50 -51
  172. package/lib/src/shared/logo-settings/components/LogoSettingsHeader.mixin.d.ts +6 -4
  173. package/lib/src/shared/logo-settings/components/LogoSettingsHeader.mixin.js +1 -0
  174. package/lib/src/shared/logo-settings/store/editable-logo-store.js +1 -1
  175. package/lib/src/shared/logo-settings/store/logo-settings-store.d.ts +1 -1
  176. package/lib/src/shared/logo-versions/LogoVersions.mixin.d.ts +13 -5
  177. package/lib/src/shared/logo-versions/LogoVersions.mixin.js +1 -0
  178. package/lib/src/shared/models.d.ts +2 -0
  179. package/lib/src/shared/my-designs/MyDesigns.mixin.d.ts +14 -6
  180. package/lib/src/shared/my-designs/MyDesigns.mixin.js +1 -0
  181. package/lib/src/shared/my-uploads/MyMedia.mixin.d.ts +14 -5
  182. package/lib/src/shared/my-uploads/MyMedia.mixin.js +1 -0
  183. package/lib/src/shared/my-uploads/MyUploads.mixin.d.ts +14 -5
  184. package/lib/src/shared/my-uploads/MyUploads.mixin.js +1 -0
  185. package/lib/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.d.ts +5 -3
  186. package/lib/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.js +1 -0
  187. package/lib/src/shared/navigation-style-settings/store/index.d.ts +2 -2
  188. package/lib/src/shared/page-navigation/store/page-navigation-store.d.ts +2 -2
  189. package/lib/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.d.ts +27 -28
  190. package/lib/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.js +0 -2
  191. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +188 -179
  192. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +181 -177
  193. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.js +1 -1
  194. package/lib/src/shared/page-settings/store/page-settings-store.d.ts +9 -9
  195. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +39 -39
  196. package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.js +0 -1
  197. package/lib/src/shared/side-bar/components/SideBar.mixin.d.ts +18 -18
  198. package/lib/src/shared/side-bar/components/SideBarTabButton.mixin.d.ts +6 -6
  199. package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +66 -60
  200. package/lib/src/shared/style-settings/store/style-settings-store.d.ts +1 -1
  201. package/lib/src/shared/style-settings/store/style-settings-store.js +1 -1
  202. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.d.ts +20 -450
  203. package/lib/src/shared/template-settings/components/TemplatesSettings.mixin.js +2 -2
  204. package/lib/src/shared/template-settings/models.d.ts +1 -0
  205. package/lib/src/shared/template-settings/store/template-settings-store.d.ts +4 -0
  206. package/lib/src/shared/template-settings/store/template-settings-store.js +79 -11
  207. package/lib/src/shared/unsplash-library/UnsplashLibrary.mixin.d.ts +9 -4
  208. package/lib/src/utils/build-asset-manifest.d.ts +4 -0
  209. package/lib/src/utils/build-asset-manifest.js +8 -0
  210. package/lib/src/utils/minify-brand-page-metadata.d.ts +0 -2
  211. package/lib/src/utils/minify-brand-page-metadata.js +2 -17
  212. package/package.json +60 -56
  213. package/src/brand-page/components/about-section/AboutSection.vue.test.ts +7 -5
  214. package/src/brand-page/components/banner-section/BannerSection.mixin.ts +210 -0
  215. package/src/brand-page/components/banner-section/BannerSection.vue +5 -1
  216. package/src/brand-page/components/brand-page-footer/BrandPageFooter.vue +1 -1
  217. package/src/brand-page/components/image/Image.mixin.ts +1 -1
  218. package/src/brand-page/components/image/Image.test.ts +1 -1
  219. package/src/brand-page/components/image-gallery/masonry/MasonryGallery.mixin.ts +1 -2
  220. package/src/brand-page/components/images-section/ImagesSection.vue +0 -1
  221. package/src/brand-page/components/logo/LogoRender.vue +188 -188
  222. package/src/brand-page/components/navigation/hamburger/HamburgerNavigation.mixin.ts +1 -0
  223. package/src/brand-page/components/navigation/navigation-side-menu/NavigationSideMenu.mixin.ts +25 -8
  224. package/src/brand-page/components/page-footer/PageFooter.vue +1 -0
  225. package/src/brand-page/components/page-header/HeaderLayout.vue +12 -6
  226. package/src/brand-page/components/page-header/PageHeader.vue +1 -0
  227. package/src/brand-page/components/shapes-section/ShapesSection.vue +1 -1
  228. package/src/brand-page/components/shop/CartModal.vue +1 -3
  229. package/src/brand-page/components/shop/FeaturedDisplay.vue +2 -2
  230. package/src/brand-page/components/shop/PaymentModal.vue +1 -5
  231. package/src/brand-page/components/shop/ProductDetailModal.vue +1 -1
  232. package/src/brand-page/components/shop/Shop.vue +1 -5
  233. package/src/brand-page/components/shop/TextDisplay.vue +1 -1
  234. package/src/brand-page/components/shop/ThumbnailDisplay.vue +2 -2
  235. package/src/brand-page/components/testimonial-section/TestimonialSection.vue +3 -3
  236. package/src/brand-page/components/text-wrapper/TextWrapper.vue +3 -1
  237. package/src/brand-page/constants/sections/footer-display.constants.ts +1 -1
  238. package/src/brand-page/models/index.ts +4 -12
  239. package/src/brand-page/models/payment.model.ts +2 -1
  240. package/src/brand-page/models/shop.model.ts +0 -2
  241. package/src/brand-page/models/user-personalisation.model.ts +1 -2
  242. package/src/brand-page/utils/__snapshots__/migration.util.test.ts.snap +3 -0
  243. package/src/brand-page/utils/__snapshots__/migration2.util.test.ts.snap +1 -0
  244. package/src/brand-page/utils/__snapshots__/model.util.test.ts.snap +2 -0
  245. package/src/brand-page/utils/migration/migration-01_1.ts +1 -1
  246. package/src/brand-page/utils/migration/migration-02.ts +0 -1
  247. package/src/brand-page/utils/migration/migration-03.ts +0 -1
  248. package/src/brand-page/utils/migration/migration-04.ts +0 -1
  249. package/src/brand-page/utils/migration/migration-05.ts +1 -5
  250. package/src/brand-page/utils/migration/migration-05_2.ts +1 -1
  251. package/src/brand-page/utils/migration/migration-08.test.ts +1 -1
  252. package/src/brand-page/utils/personalisation.util.test.ts +35 -0
  253. package/src/brand-page/utils/personalisation.util.ts +119 -23
  254. package/src/brand-page/view-models.ts +38 -56
  255. package/src/brand-page-maker/assessors/banner-section-description-visibility.assessor.ts +6 -6
  256. package/src/brand-page-maker/assessors/color-replacement-icon-visibility.assessor.ts +2 -2
  257. package/src/brand-page-maker/assessors/color-replacement-profile-visibility.assessor.ts +2 -2
  258. package/src/brand-page-maker/assessors/color-replacement-visibility.assessor.ts +2 -2
  259. package/src/brand-page-maker/assessors/contact-form-visibility.assessor.ts +14 -14
  260. package/src/brand-page-maker/components/action-bar/ActionBar.mixin.ts +1 -0
  261. package/src/brand-page-maker/components/ai-text-edit/AiActionButtons.vue +27 -12
  262. package/src/brand-page-maker/components/ai-text-edit/AiChatbox.vue +3 -2
  263. package/src/brand-page-maker/components/ai-text-edit/TextBubble.vue +8 -7
  264. package/src/brand-page-maker/components/ai-website-builder/AiWebsiteBuilder.vue +21 -1
  265. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +5 -1
  266. package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.stories.ts +1 -0
  267. package/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.stories.ts +2 -5
  268. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-examples.ts +0 -5
  269. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-page-payment.ts +0 -8
  270. package/src/brand-page-maker/components/brand-page-maker/__fixtures__/brand-site-template.examples.ts +0 -2
  271. package/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.vue +1 -0
  272. package/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.ts +1 -1
  273. package/src/brand-page-maker/components/color-palette/BpColorPalette.vue +1 -2
  274. package/src/brand-page-maker/components/color-picker/components/ColorModeSelect.mixin.ts +1 -0
  275. package/src/brand-page-maker/components/color-picker/components/GradientColorSlider.mixin.ts +1 -0
  276. package/src/brand-page-maker/components/color-picker/components/GradientColorSliderHandler.mixin.ts +1 -0
  277. package/src/brand-page-maker/components/color-picker/components/GradientTypeSelector.mixin.ts +1 -0
  278. package/src/brand-page-maker/components/device/Device.mixin.ts +1 -0
  279. package/src/brand-page-maker/components/navigation/Navigation.mixin.ts +1 -0
  280. package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +3 -1
  281. package/src/brand-page-maker/components/sensitive-content/SensitiveContent.vue +1 -4
  282. package/src/brand-page-maker/components/seo-settings/DeleteDomainModal.vue +1 -1
  283. package/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.ts +1 -0
  284. package/src/brand-page-maker/components/seo-settings/SeoPageSettings.vue +1 -1
  285. package/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.ts +0 -1
  286. package/src/brand-page-maker/components/seo-settings/UrlSettings.vue +0 -1
  287. package/src/brand-page-maker/components/seo-settings/UseExistingDomainModal.vue +1 -5
  288. package/src/brand-page-maker/components/shop/AddOrEditProductContainer.vue +1 -1
  289. package/src/brand-page-maker/components/shop/ReplaceImageSettingsForShop.vue +1 -1
  290. package/src/brand-page-maker/components/social-share/SocialShare.vue +1 -1
  291. package/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.ts +22 -8
  292. package/src/brand-page-maker/components/template-preview/TemplatePreview.vue +5 -10
  293. package/src/brand-page-maker/components/template-preview/TemplatePreviewAiBadge.vue +12 -0
  294. package/src/brand-page-maker/components/video-play/VideoPlayButton.vue +1 -1
  295. package/src/brand-page-maker/composables/ai-chat/types.ts +6 -0
  296. package/src/brand-page-maker/composables/ai-chat/ui-actions.test.ts +80 -0
  297. package/src/brand-page-maker/composables/ai-chat/ui-actions.ts +58 -0
  298. package/src/brand-page-maker/composables/ai-chat/useAiWebsiteBuilderChat.ts +308 -262
  299. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +6 -6
  300. package/src/brand-page-maker/composables/useEventTracker.ts +1 -0
  301. package/src/brand-page-maker/constants/config-settings-constant.ts +5 -5
  302. package/src/brand-page-maker/convertors/text-image-display-style.convertor.ts +1 -1
  303. package/src/brand-page-maker/models/button-styles-config.ts +4 -2
  304. package/src/brand-page-maker/models/content-settings-configs.ts +4 -2
  305. package/src/brand-page-maker/models/navigation-style-configs.ts +5 -6
  306. package/src/brand-page-maker/stores/admin-logo-settings/admin-logo-settings-store.ts +0 -1
  307. package/src/brand-page-maker/stores/brandpage-container/brand-page-container-store.ts +8 -5
  308. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +1 -3
  309. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +12 -4
  310. package/src/brand-page-maker/stores/ui/ui-store.ts +16 -0
  311. package/src/brand-page-maker/utils/content-settings.util.ts +1 -1
  312. package/src/brand-page-maker/utils/rich-text-editor.util.ts +4 -4
  313. package/src/clients/ai-assistant-client.ts +7 -0
  314. package/src/clients/design-template-client.ts +3 -0
  315. package/src/clients/models.ts +2 -0
  316. package/src/composables/useSnapshot.ts +19 -22
  317. package/src/lib.ts +12 -0
  318. package/src/metadata-builder/builders/footer-builder.test.ts +130 -229
  319. package/src/metadata-builder/builders/footer-builder.ts +155 -90
  320. package/src/metadata-builder/builders/section-builders/image-gallery-builder.ts +88 -62
  321. package/src/metadata-builder/builders/section-builders/images-section-builder.ts +129 -66
  322. package/src/metadata-builder/builders/section-builders/shapes-section-builder.ts +160 -105
  323. package/src/metadata-builder/builders/section-builders/social-links-builder.ts +20 -65
  324. package/src/metadata-builder/builders/section-builders/testimonial-section-builder.ts +146 -83
  325. package/src/metadata-builder/builders/section-builders/text-section-builder.ts +122 -70
  326. package/src/metadata-builder/builders/section-field-utils.ts +1 -1
  327. package/src/metadata-builder/builders/shape-color-utils.ts +2 -2
  328. package/src/metadata-builder/parsers/ai-toolcall-parser.ts +7 -16
  329. package/src/metadata-builder/parsers/section-tool-arguments.ts +48 -66
  330. package/src/plugins/google-maps-plugin/google-maps-plugin.ts +8 -8
  331. package/src/shared/background-settings/components/BackgroundSettings.vue +1 -1
  332. package/src/shared/background-settings/components/background-color/BackgroundColorSettings.vue +1 -1
  333. package/src/shared/color-picker/components/ColorPicker.mixin.ts +2 -7
  334. package/src/shared/color-picker/components/ColorPickerSwatch.mixin.ts +1 -0
  335. package/src/shared/common/NumberInput.vue +1 -0
  336. package/src/shared/common/SideBarSettingsHeader.vue +2 -2
  337. package/src/shared/confirm-modal/ConfirmModal.mixin.ts +1 -0
  338. package/src/shared/content-settings/components/booking-url-field/BookingUrlField.vue +1 -0
  339. package/src/shared/content-settings/components/button-configuration-field/ButtonConfigurationField.vue +1 -0
  340. package/src/shared/content-settings/components/color-field/ColorField.vue +3 -10
  341. package/src/shared/content-settings/components/content-settings/ContentSettings.mixin.ts +1 -1
  342. package/src/shared/content-settings/components/content-settings/ContentSettingsLockedButton.vue +1 -0
  343. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.ts +5 -0
  344. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.ts +1 -14
  345. package/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.ts +4 -6
  346. package/src/shared/content-settings/components/icon-library/IconLibrary.mixin.ts +1 -0
  347. package/src/shared/content-settings/components/items-field/ItemsField.mixin.ts +1 -1
  348. package/src/shared/content-settings/components/logo-selection-field/LogoSelectionField.vue +1 -1
  349. package/src/shared/content-settings/components/logo-size-field/LogoSizeSliderField.vue +1 -1
  350. package/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.vue +1 -1
  351. package/src/shared/content-settings/components/personalisation-role-field/PersonalisationRoleField.vue +4 -4
  352. package/src/shared/content-settings/components/text-image-field/TextImageField.vue +2 -8
  353. package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.ts +1 -1
  354. package/src/shared/content-settings/models.ts +3 -2
  355. package/src/shared/content-settings/utils.ts +0 -1
  356. package/src/shared/dropzone-image-uploader/components/DropzoneImageUploader.vue +1 -0
  357. package/src/shared/ecommerce-settings/store/cart-store.test.ts +1 -1
  358. package/src/shared/font-family-selector/FontFamilySelector.mixin.ts +1 -0
  359. package/src/shared/image-gallery-style-settings/ImageGalleryStyleSettings.mixin.ts +1 -0
  360. package/src/shared/logo-settings/components/EditLogoSettings.mixin.ts +1 -1
  361. package/src/shared/logo-settings/components/LogoSettings.mixin.ts +0 -1
  362. package/src/shared/logo-settings/components/LogoSettingsHeader.mixin.ts +1 -0
  363. package/src/shared/logo-settings/components/LogoStyleSettingsWithState.vue +2 -2
  364. package/src/shared/logo-settings/components/LogoTemplateSearch.vue +1 -1
  365. package/src/shared/logo-settings/store/editable-logo-store.ts +1 -1
  366. package/src/shared/logo-settings/store/logo-settings-store.test.ts +4 -4
  367. package/src/shared/logo-versions/LogoVersions.mixin.ts +1 -0
  368. package/src/shared/models.ts +6 -0
  369. package/src/shared/my-designs/MyDesigns.mixin.ts +1 -0
  370. package/src/shared/my-uploads/MyMedia.mixin.ts +1 -0
  371. package/src/shared/my-uploads/MyMediaSelectionItem.vue +2 -1
  372. package/src/shared/my-uploads/MyUploads.mixin.ts +1 -0
  373. package/src/shared/my-uploads/models.ts +1 -2
  374. package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.mixin.ts +1 -0
  375. package/src/shared/navigation-style-settings/components/navigation-style-settings/NavigationStyleSettings.vue +1 -1
  376. package/src/shared/page-settings/components/new-page-modal/NewPageModal.mixin.ts +0 -3
  377. package/src/shared/page-settings/components/page-settings/NestedDraggable.vue +1 -1
  378. package/src/shared/page-settings/components/page-settings/PageSettings.vue +1 -2
  379. package/src/shared/page-settings/components/page-settings-section-styles/HeaderDisplayStyle.vue +1 -1
  380. package/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.ts +1 -1
  381. package/src/shared/page-settings/store/page-settings-store.test.ts +4 -8
  382. package/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.ts +0 -1
  383. package/src/shared/shape-library/ShapeLibrary.vue +2 -2
  384. package/src/shared/style-settings/store/style-settings-store.ts +1 -1
  385. package/src/shared/template-settings/components/TemplatesSettings.mixin.ts +2 -2
  386. package/src/shared/template-settings/models.ts +1 -0
  387. package/src/shared/template-settings/store/template-settings-store.ts +105 -18
  388. package/src/shared/unsplash-library/UnsplashLibrary.vue +2 -6
  389. package/src/shared/video-library/VideoLibrary.vue +1 -1
  390. package/src/utils/build-asset-manifest.ts +12 -0
  391. package/src/utils/minify-brand-page-metadata.ts +7 -27
  392. package/lib/src/metadata-builder/builders/item-id-utils.d.ts +0 -54
  393. package/lib/src/metadata-builder/builders/item-id-utils.js +0 -96
  394. package/src/metadata-builder/builders/item-id-utils.test.ts +0 -184
  395. package/src/metadata-builder/builders/item-id-utils.ts +0 -117
@@ -1,4 +1,4 @@
1
- import { ref, computed, watch, nextTick, onUnmounted } from 'vue';
1
+ import { ref, computed, watch, nextTick } from 'vue';
2
2
  import type { BrandPageModel } from '../../../brand-page/models';
3
3
  import {
4
4
  getInstance as getAiAssistantClient,
@@ -18,8 +18,8 @@ import {
18
18
  type PlanItem,
19
19
  } from '../../../clients/websocket-gateway-client';
20
20
  import { minifyBrandPageMetadata } from '../../../utils/minify-brand-page-metadata';
21
- import { ensureBrandPageItemIds } from '../../../metadata-builder/builders/item-id-utils';
22
21
  import { buildAssetManifest } from '../../../utils/build-asset-manifest';
22
+ import cloneDeep from 'lodash.clonedeep';
23
23
  import { usePageNavigationStore } from '../../../shared/page-navigation/store/page-navigation-store';
24
24
  import { navigateToPageByPageId } from '../../routing';
25
25
  import {
@@ -47,7 +47,9 @@ import type {
47
47
  ThreadMessage,
48
48
  TextThreadMessage,
49
49
  SendMessageOptions,
50
+ AgentAction,
50
51
  } from './types';
52
+ import { partitionAiToolCalls } from './ui-actions';
51
53
 
52
54
  const BUILD_TIMEOUT_MS = 600000;
53
55
 
@@ -257,11 +259,6 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
257
259
 
258
260
  const buildMessagePayload = async (userPrompt: string) => {
259
261
  const brandPageData = brandPageMakerStore.brandPageData;
260
-
261
- // BP-5603: stamp stable uuid ids onto every nested item BEFORE minifying,
262
- // so the id the AI is shown (and returns as `item_id`) is the exact id the
263
- // executor matches when applying tool calls to this same live model.
264
- ensureBrandPageItemIds(brandPageData);
265
262
  const headerLogoDraftToken =
266
263
  brandPageData.pageHeaderDesktop?.logoImage?.logoDraftToken ??
267
264
  uiStore.logoDraftToken;
@@ -274,6 +271,7 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
274
271
 
275
272
  const websiteContext = {
276
273
  metadata: minifyBrandPageMetadata(brandPageData, assets),
274
+ metadataFull: cloneDeep(brandPageData),
277
275
  ...(assets.length > 0 && { assets }),
278
276
  websiteTemplateToken: containerStore.designTemplateToken,
279
277
  ...(containerStore.designDraftToken && {
@@ -467,7 +465,11 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
467
465
  const callApiBuildAsync = async (
468
466
  userPrompt: string,
469
467
  userMessageId: string,
470
- ): Promise<{ text: string | null; isError?: boolean }> => {
468
+ ): Promise<{
469
+ text: string | null;
470
+ isError?: boolean;
471
+ actions?: AgentAction[];
472
+ }> => {
471
473
  const connectionId = await ensureConnectedAsync();
472
474
  const wsClient = activeBuildWsClient!;
473
475
 
@@ -538,296 +540,323 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
538
540
  });
539
541
  }
540
542
 
541
- return new Promise<{ text: string | null; isError?: boolean }>(
542
- (resolve, reject) => {
543
- let settled = false;
544
- let retryCount = 0;
545
- let lastAiMessage: string | null = null;
546
- let handler: ((msg: WebSocketMessage) => void) | null = null;
547
- // Vacant-slot queue scoped to this build session. Persists across
548
- // retry rounds so a failed CREATE returns to its planned slot via
549
- // a synthesised `move_before_content_id`.
550
- const vacantSlots: VacantSlotMap = new Map();
551
-
552
- const finishBuild = () => {
553
- aiThreadStore.isBuildInProgress = false;
554
- wsClient.setBuildActive(false);
555
- wsClient.stopResponseHeartbeat();
556
-
557
- if (handler) wsClient.offMessage(handler);
558
- };
559
-
560
- const timeout = setTimeout(() => {
561
- if (settled) return;
543
+ return new Promise<{
544
+ text: string | null;
545
+ isError?: boolean;
546
+ actions?: AgentAction[];
547
+ }>((resolve, reject) => {
548
+ let settled = false;
549
+ let retryCount = 0;
550
+ let lastAiMessage: string | null = null;
551
+ let lastActions: AgentAction[] | undefined;
552
+ let handler: ((msg: WebSocketMessage) => void) | null = null;
553
+ // Vacant-slot queue scoped to this build session. Persists across
554
+ // retry rounds so a failed CREATE returns to its planned slot via
555
+ // a synthesised `move_before_content_id`.
556
+ const vacantSlots: VacantSlotMap = new Map();
557
+
558
+ const finishBuild = () => {
559
+ aiThreadStore.isBuildInProgress = false;
560
+ wsClient.setBuildActive(false);
561
+ wsClient.stopResponseHeartbeat();
562
+
563
+ if (handler) wsClient.offMessage(handler);
564
+ };
562
565
 
563
- settled = true;
564
- finishBuild();
565
- reject(new Error('Build timeout'));
566
- }, BUILD_TIMEOUT_MS);
566
+ const timeout = setTimeout(() => {
567
+ if (settled) return;
567
568
 
568
- handler = (msg: WebSocketMessage) => {
569
- if (settled) return;
569
+ settled = true;
570
+ finishBuild();
571
+ reject(new Error('Build timeout'));
572
+ }, BUILD_TIMEOUT_MS);
570
573
 
571
- try {
572
- if (msg.buildId !== aiThreadStore.buildId) return;
574
+ // Transition the build to "done" exactly once (idempotent). Returns
575
+ // false when already settled, so callers can early-return.
576
+ const markDone = (): boolean => {
577
+ if (settled) return false;
573
578
 
574
- if (isStopped.value) {
575
- settled = true;
576
- clearTimeout(timeout);
577
- finishBuild();
578
- resolve({ text: null });
579
+ settled = true;
580
+ clearTimeout(timeout);
581
+ finishBuild();
579
582
 
580
- return;
581
- }
583
+ return true;
584
+ };
582
585
 
583
- if (msg.type === 'chat_started' && msg.message) {
584
- withTypingMessage((m) => {
585
- m.initialMessage = msg.message;
586
- });
586
+ // The single terminal path. Every resolve goes through here, so "where
587
+ // does this Promise settle?" has one answer.
588
+ const settle = (result: {
589
+ text: string | null;
590
+ isError?: boolean;
591
+ actions?: AgentAction[];
592
+ }): void => {
593
+ if (markDone()) resolve(result);
594
+ };
587
595
 
588
- return;
589
- }
596
+ // Streaming progress frames mutate the in-flight typing bubble and never
597
+ // settle the build. Returns true when `msg` was a progress frame.
598
+ const applyProgressUpdate = (msg: WebSocketMessage): boolean => {
599
+ if (msg.type === 'chat_started' && msg.message) {
600
+ withTypingMessage((m) => {
601
+ m.initialMessage = msg.message;
602
+ });
590
603
 
591
- if (msg.type === 'plan_announced' && msg.items) {
592
- withTypingMessage((m) => {
593
- if (!m.planItems) m.planItems = msg.items as PlanItem[];
594
- });
604
+ return true;
605
+ }
595
606
 
596
- return;
597
- }
607
+ if (msg.type === 'plan_announced' && msg.items) {
608
+ withTypingMessage((m) => {
609
+ if (!m.planItems) m.planItems = msg.items as PlanItem[];
610
+ });
598
611
 
599
- if (msg.type === 'item_complete' && msg.itemId) {
600
- const itemId = msg.itemId;
612
+ return true;
613
+ }
601
614
 
602
- withTypingMessage((m) => {
603
- if (!m.completedItemIds?.includes(itemId)) {
604
- m.completedItemIds = [
605
- ...(m.completedItemIds ?? []),
606
- itemId,
607
- ];
608
- }
609
- });
615
+ if (msg.type === 'item_complete' && msg.itemId) {
616
+ const itemId = msg.itemId;
610
617
 
611
- return;
618
+ withTypingMessage((m) => {
619
+ if (!m.completedItemIds?.includes(itemId)) {
620
+ m.completedItemIds = [...(m.completedItemIds ?? []), itemId];
612
621
  }
622
+ });
613
623
 
614
- if (msg.type === 'server_response') {
615
- const toolCalls = (msg.toolCalls ||
616
- []) as AiAssistantToolCall[];
617
- const aiResponse: AiAssistantResponse = {
618
- threadId: aiThreadStore.threadId || '',
619
- toolCalls,
620
- message: msg.message || null,
621
- type: 'tool_calls',
622
- totalPaidToolCalls: 0,
623
- timestamp: Date.now(),
624
- };
625
-
626
- (async () => {
627
- try {
628
- // No tool calls = build cycle complete (success, max retries, or no retryable sections)
629
- if (toolCalls.length === 0) {
630
- // Defence-in-depth: a server_response with no toolCalls AND
631
- // no message text is a degenerate response — it means the
632
- // backend graph reached END without producing anything
633
- // actionable. The server-side fix in stream_with_push now
634
- // converts this to a build_error frame, but if a future
635
- // regression slips through we must NOT show "Your website
636
- // has been updated" — that hides real failures from users
637
- // and from monitoring.
638
- const hasMeaningfulMessage = Boolean(
639
- aiResponse.message || lastAiMessage,
640
- );
641
-
642
- if (!hasMeaningfulMessage) {
643
- raygunUtil.safeSendRaygunError(
644
- new Error(
645
- 'AI build server_response had empty toolCalls and empty message',
646
- ),
647
- {
648
- tags: [
649
- 'feature:ai-website-builder',
650
- 'failure:degenerate_server_response',
651
- ],
652
- customData: {
653
- build_id: aiThreadStore.buildId ?? null,
654
- thread_id: aiThreadStore.threadId ?? null,
655
- },
656
- },
657
- );
658
- settled = true;
659
- clearTimeout(timeout);
660
- finishBuild();
661
- resolve({
662
- text: 'Something went wrong while updating your website. Please try again.',
663
- isError: true,
664
- });
665
-
666
- return;
667
- }
668
-
669
- settled = true;
670
- clearTimeout(timeout);
671
- finishBuild();
672
- resolve({
673
- text: aiResponse.message || lastAiMessage || '',
674
- });
675
-
676
- return;
677
- }
678
-
679
- // Tool calls present — apply locally and submit results back
680
- const { toolResults, aiMessage } =
681
- await applyToolCallsAsync(
682
- aiResponse,
683
- userMessageId,
684
- vacantSlots,
685
- );
686
-
687
- lastAiMessage = aiMessage;
688
-
689
- // Submit all tool results (success + failure) so the AI pipeline
690
- // persists ToolMessages matching every tool_call in the conversation.
691
- const failedResults = toolResults.filter(
692
- (tr) => tr.success !== 'success',
693
- );
694
-
695
- aiLogger.log('tool submission for results', {
696
- total: toolResults.length,
697
- failed: failedResults.length,
698
- failedResults,
699
- retryCount,
700
- });
701
-
702
- const submitResult =
703
- await client.submitToolResultsBuildAsync(
704
- aiThreadStore.threadId!,
705
- {
706
- toolCalls: toolResults,
707
- agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER,
708
- connectionId,
709
- retryCount,
710
- userPlan,
711
- },
712
- );
713
-
714
- if (failedResults.length === 0) {
715
- settled = true;
716
- clearTimeout(timeout);
717
- finishBuild();
718
- resolve({
719
- text: aiMessage || 'Your website has been updated.',
720
- });
721
-
722
- return;
723
- }
724
-
725
- // Update buildId so the handler matches subsequent WS messages
726
- if (submitResult.buildId) {
727
- aiThreadStore.buildId = submitResult.buildId;
728
- }
729
-
730
- // eslint-disable-next-line no-plusplus
731
- retryCount++;
732
- } catch (err) {
733
- aiLogger.log('server_response apply error', { err });
734
- // Client-side apply failure (metadata builder, tool-call parser,
735
- // missing field, etc.) — server thinks the build succeeded but we
736
- // couldn't materialise the changes. Mark the chat bubble as an
737
- // error so the user sees the real outcome, and report to Raygun
738
- // so the failure is visible in monitoring (the server didn't see it).
739
- raygunUtil.safeSendRaygunError(
740
- err instanceof Error
741
- ? err
742
- : new Error('AI apply failed: non-Error thrown'),
743
- {
744
- tags: [
745
- 'feature:ai-website-builder',
746
- 'failure:apply_error',
747
- 'stage:client_apply',
748
- ],
749
- customData: {
750
- thread_id: aiThreadStore.threadId ?? null,
751
- build_id: aiThreadStore.buildId ?? null,
752
- },
753
- },
754
- );
755
- settled = true;
756
- clearTimeout(timeout);
757
- finishBuild();
758
- resolve({
759
- text: "I couldn't apply those changes to your website. Please try again.",
760
- isError: true,
761
- });
762
- }
763
- })();
764
-
765
- return;
766
- }
624
+ return true;
625
+ }
767
626
 
768
- if (msg.type === 'server_error' || msg.type === 'build_error') {
769
- settled = true;
770
- clearTimeout(timeout);
771
- finishBuild();
772
-
773
- // Backend already reports the underlying pipeline failure to
774
- // Raygun via its structured handler (stage:run_build /
775
- // stage:section_builder / etc. with full Python traceback).
776
- // We report the frontend's RECEIPT of the error frame as a
777
- // separate signal — distinct tag, distinct grouping. This
778
- // gives triangulation: both sides have entry → normal crash;
779
- // frontend only → backend Raygun outage; backend only → WS
780
- // frame didn't reach client (different bug shape).
781
- const wsMsg = msg as {
782
- type: string;
783
- code?: string;
784
- message?: string;
785
- error?: string;
786
- buildId?: string;
787
- };
627
+ return false;
628
+ };
788
629
 
630
+ // Apply one round of build tool calls: settle on completion/failure, or
631
+ // bump retryCount so the handler processes the next round's frame.
632
+ const processServerResponse = async (
633
+ aiResponse: AiAssistantResponse,
634
+ ): Promise<void> => {
635
+ const toolCalls = aiResponse.toolCalls ?? [];
636
+
637
+ try {
638
+ // No tool calls = build cycle complete (success, max retries, or no retryable sections).
639
+ if (toolCalls.length === 0) {
640
+ // Defence-in-depth: empty toolCalls AND empty message is a
641
+ // degenerate response (graph reached END producing nothing). Never
642
+ // show "Your website has been updated" — it hides real failures.
643
+ const hasMeaningfulMessage = Boolean(
644
+ aiResponse.message || lastAiMessage,
645
+ );
646
+
647
+ if (!hasMeaningfulMessage) {
789
648
  raygunUtil.safeSendRaygunError(
790
649
  new Error(
791
- `AI build ${wsMsg.type}: ${wsMsg.code ?? wsMsg.error ?? 'unknown'}`,
650
+ 'AI build server_response had empty toolCalls and empty message',
792
651
  ),
793
652
  {
794
653
  tags: [
795
654
  'feature:ai-website-builder',
796
- 'failure:websocket_error_received',
797
- `frame_type:${wsMsg.type}`,
655
+ 'failure:degenerate_server_response',
798
656
  ],
799
657
  customData: {
800
- code: wsMsg.code ?? null,
801
- message: wsMsg.message ?? null,
802
- error: wsMsg.error ?? null,
803
- build_id: wsMsg.buildId ?? null,
658
+ build_id: aiThreadStore.buildId ?? null,
804
659
  thread_id: aiThreadStore.threadId ?? null,
805
660
  },
806
661
  },
807
662
  );
808
-
809
- resolve({ text: pickWsErrorMessage(msg), isError: true });
663
+ settle({
664
+ text: 'Something went wrong while updating your website. Please try again.',
665
+ isError: true,
666
+ });
810
667
 
811
668
  return;
812
669
  }
813
- } catch (err) {
814
- aiLogger.log('Unexpected error in WS message handler', {
815
- err,
816
- type: msg.type,
670
+
671
+ // Mark settled BEFORE the await so concurrent frames are ignored.
672
+ if (!markDone()) return;
673
+
674
+ await snapshotStore.refreshSnapshotAsync();
675
+ resolve({
676
+ text: aiResponse.message || lastAiMessage || '',
677
+ actions: lastActions,
817
678
  });
818
679
 
819
- if (!settled) {
820
- settled = true;
821
- clearTimeout(timeout);
822
- finishBuild();
823
- resolve({ text: 'An error occurred during the build.' });
824
- }
680
+ return;
825
681
  }
682
+
683
+ // Tool calls present — apply locally and submit results back.
684
+ const { toolResults, aiMessage } = await applyToolCallsAsync(
685
+ aiResponse,
686
+ userMessageId,
687
+ vacantSlots,
688
+ );
689
+
690
+ lastAiMessage = aiMessage;
691
+
692
+ // Submit all tool results (success + failure) so the AI pipeline
693
+ // persists ToolMessages matching every tool_call in the conversation.
694
+ const failedResults = toolResults.filter(
695
+ (tr) => tr.success !== 'success',
696
+ );
697
+
698
+ aiLogger.log('tool submission for results', {
699
+ total: toolResults.length,
700
+ failed: failedResults.length,
701
+ failedResults,
702
+ retryCount,
703
+ });
704
+
705
+ const submitResult = await client.submitToolResultsBuildAsync(
706
+ aiThreadStore.threadId!,
707
+ {
708
+ toolCalls: toolResults,
709
+ agentType: AI_ASSISTANT_AGENT_TYPES.WEBSITE_BUILDER,
710
+ connectionId,
711
+ retryCount,
712
+ userPlan,
713
+ },
714
+ );
715
+
716
+ if (failedResults.length === 0) {
717
+ settle({
718
+ text: aiMessage || 'Your website has been updated.',
719
+ actions: lastActions,
720
+ });
721
+
722
+ return;
723
+ }
724
+
725
+ // Failed sections will retry: refresh buildId so the handler matches
726
+ // the next round's frames, and count the round.
727
+ if (submitResult.buildId) {
728
+ aiThreadStore.buildId = submitResult.buildId;
729
+ }
730
+
731
+ retryCount += 1;
732
+ } catch (err) {
733
+ aiLogger.log('server_response apply error', { err });
734
+ // Client-side apply failure (metadata builder, tool-call parser,
735
+ // missing field, etc.) — the server thinks the build succeeded but we
736
+ // couldn't materialise the changes. Surface it and report to Raygun
737
+ // (the server didn't see this failure).
738
+ raygunUtil.safeSendRaygunError(
739
+ err instanceof Error
740
+ ? err
741
+ : new Error('AI apply failed: non-Error thrown'),
742
+ {
743
+ tags: [
744
+ 'feature:ai-website-builder',
745
+ 'failure:apply_error',
746
+ 'stage:client_apply',
747
+ ],
748
+ customData: {
749
+ thread_id: aiThreadStore.threadId ?? null,
750
+ build_id: aiThreadStore.buildId ?? null,
751
+ },
752
+ },
753
+ );
754
+ settle({
755
+ text: "I couldn't apply those changes to your website. Please try again.",
756
+ isError: true,
757
+ });
758
+ }
759
+ };
760
+
761
+ const handleBuildError = (msg: WebSocketMessage): void => {
762
+ if (!markDone()) return;
763
+
764
+ // Backend already reports the underlying pipeline failure to Raygun
765
+ // (with full traceback). We report the frontend's RECEIPT of the error
766
+ // frame as a separate signal — distinct tag/grouping — for triangulation:
767
+ // both sides → normal crash; frontend only → backend Raygun outage;
768
+ // backend only → WS frame didn't reach client.
769
+ const wsMsg = msg as {
770
+ type: string;
771
+ code?: string;
772
+ message?: string;
773
+ error?: string;
774
+ buildId?: string;
826
775
  };
827
776
 
828
- wsClient.onMessage(handler);
829
- },
830
- );
777
+ raygunUtil.safeSendRaygunError(
778
+ new Error(
779
+ `AI build ${wsMsg.type}: ${wsMsg.code ?? wsMsg.error ?? 'unknown'}`,
780
+ ),
781
+ {
782
+ tags: [
783
+ 'feature:ai-website-builder',
784
+ 'failure:websocket_error_received',
785
+ `frame_type:${wsMsg.type}`,
786
+ ],
787
+ customData: {
788
+ code: wsMsg.code ?? null,
789
+ message: wsMsg.message ?? null,
790
+ error: wsMsg.error ?? null,
791
+ build_id: wsMsg.buildId ?? null,
792
+ thread_id: aiThreadStore.threadId ?? null,
793
+ },
794
+ },
795
+ );
796
+
797
+ resolve({ text: pickWsErrorMessage(msg), isError: true });
798
+ };
799
+
800
+ // Single dispatch point: ignore stale/already-settled frames, then route
801
+ // by frame kind. Progress frames update the bubble; server_response and
802
+ // error frames are the only ones that can settle the build.
803
+ handler = (msg: WebSocketMessage) => {
804
+ if (settled) return;
805
+
806
+ try {
807
+ if (msg.buildId !== aiThreadStore.buildId) return;
808
+
809
+ if (isStopped.value) {
810
+ settle({ text: null });
811
+
812
+ return;
813
+ }
814
+
815
+ if (applyProgressUpdate(msg)) return;
816
+
817
+ if (msg.type === 'server_response') {
818
+ // CTA buttons (e.g. Upgrade) ride in toolCalls but are presentation,
819
+ // not page edits. Split them out so only real mutations reach the
820
+ // metadata-builder and the tool-result submission — a UI action must
821
+ // never be answered with a tool result (it isn't in the agent's
822
+ // conversation), or the next turn on the thread fails.
823
+ const { mutationToolCalls, actions } = partitionAiToolCalls(
824
+ (msg.toolCalls || []) as AiAssistantToolCall[],
825
+ );
826
+
827
+ if (actions.length) lastActions = actions;
828
+
829
+ void processServerResponse({
830
+ threadId: aiThreadStore.threadId || '',
831
+ toolCalls: mutationToolCalls,
832
+ message: msg.message || null,
833
+ type: 'tool_calls',
834
+ totalPaidToolCalls: 0,
835
+ timestamp: Date.now(),
836
+ });
837
+
838
+ return;
839
+ }
840
+
841
+ if (msg.type === 'server_error' || msg.type === 'build_error') {
842
+ handleBuildError(msg);
843
+
844
+ return;
845
+ }
846
+ } catch (err) {
847
+ aiLogger.log('Unexpected error in WS message handler', {
848
+ err,
849
+ type: msg.type,
850
+ });
851
+ settle({
852
+ text: 'An error occurred during the build.',
853
+ isError: true,
854
+ });
855
+ }
856
+ };
857
+
858
+ wsClient.onMessage(handler);
859
+ });
831
860
  } catch (err) {
832
861
  aiThreadStore.isBuildInProgress = false;
833
862
  wsClient.setBuildActive(false);
@@ -927,6 +956,18 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
927
956
  if (result.isError) {
928
957
  threadItems.value[messageIndex].isError = true;
929
958
  }
959
+
960
+ // Attach agent-driven actions (e.g. upgrade CTA) only on successful
961
+ // (non-error) responses. Suppressed for premium users client-side as
962
+ // a defence-in-depth guard (server also vetoes via eligibility logic).
963
+ if (
964
+ !result.isError &&
965
+ result.actions?.length &&
966
+ !userStore.hasPremiumSubscription
967
+ ) {
968
+ (threadItems.value[messageIndex] as TextThreadMessage).actions =
969
+ result.actions;
970
+ }
930
971
  } else {
931
972
  threadItems.value[messageIndex].text =
932
973
  'Failed to apply changes. Please try again.';
@@ -1028,6 +1069,11 @@ export function useAiWebsiteBuilderChat(): UseAiChatResult {
1028
1069
  completedItemIds:
1029
1070
  (msg as TextThreadMessage).completedItemIds ?? [],
1030
1071
  }),
1072
+ ...(msg.type === 'text' &&
1073
+ !msg.isTyping &&
1074
+ (msg as TextThreadMessage).actions?.length && {
1075
+ actions: (msg as TextThreadMessage).actions,
1076
+ }),
1031
1077
  } as Record<string, unknown>,
1032
1078
  };
1033
1079
  });