@gengage/assistant-fe 0.5.7 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/dist/agentic/adaptor/create-adaptor.d.ts +19 -0
  2. package/dist/agentic/adaptor/fetch-bridge.d.ts +11 -0
  3. package/dist/agentic/adaptor/mount.d.ts +38 -0
  4. package/dist/agentic/context/chat-context.d.ts +15 -0
  5. package/dist/agentic/context/context-store.d.ts +20 -0
  6. package/dist/agentic/context/persistence.d.ts +12 -0
  7. package/dist/agentic/events/builders.d.ts +10 -0
  8. package/dist/agentic/events/error-taxonomy.d.ts +27 -0
  9. package/dist/agentic/events/product-normalize.d.ts +47 -0
  10. package/dist/agentic/events/ui-specs.d.ts +37 -0
  11. package/dist/agentic/flow/beauty-consulting-turn.d.ts +1 -0
  12. package/dist/agentic/flow/create-flow.d.ts +2 -0
  13. package/dist/agentic/flow/dispatch.d.ts +3 -0
  14. package/dist/agentic/index.d.ts +18 -0
  15. package/dist/agentic/index.js +620 -0
  16. package/dist/agentic/types.d.ts +212 -0
  17. package/dist/agentic/util/assistant-host.d.ts +11 -0
  18. package/dist/agentic/util/be-url.d.ts +4 -0
  19. package/dist/agentic/util/browser-memory.d.ts +13 -0
  20. package/dist/agentic/util/browser-tools.d.ts +31 -0
  21. package/dist/agentic/util/lazy-runtime-loader.d.ts +9 -0
  22. package/dist/agentic/util/request-text.d.ts +3 -0
  23. package/dist/agentic/util/time.d.ts +2 -0
  24. package/dist/agentic/worker/be-client.d.ts +15 -0
  25. package/dist/agentic/worker/entry.d.ts +2 -0
  26. package/dist/agentic/worker/flow-runner.d.ts +24 -0
  27. package/dist/agentic/worker/jwt-mint.d.ts +21 -0
  28. package/dist/agentic/worker/rpc.d.ts +24 -0
  29. package/dist/agentic/worker/tool-bridge.d.ts +2 -0
  30. package/dist/agentic/worker.d.ts +16 -0
  31. package/dist/agentic/worker.js +119 -0
  32. package/dist/agentic.iife.js +5 -0
  33. package/dist/{api-paths-CwzwbgQZ.js → api-paths-DJFF9RuZ.js} +1 -1
  34. package/dist/beauty-consulting-turn-BmPXbkQg.js +1019 -0
  35. package/dist/chat/api.d.ts +17 -0
  36. package/dist/chat/assistant-mode.d.ts +20 -0
  37. package/dist/chat/attachment-utils.d.ts +9 -0
  38. package/dist/chat/catalog.d.ts +455 -0
  39. package/dist/chat/chat-presentation-state.d.ts +53 -0
  40. package/dist/chat/components/AIGroupingCards.d.ts +15 -0
  41. package/dist/chat/components/AISuggestedSearchCards.d.ts +13 -0
  42. package/dist/chat/components/AITopPicks.d.ts +9 -0
  43. package/dist/chat/components/BeautyPhotoStep.d.ts +31 -0
  44. package/dist/chat/components/CategoriesContainer.d.ts +11 -0
  45. package/dist/chat/components/ChatDrawer.d.ts +362 -0
  46. package/dist/chat/components/ChoicePrompter.d.ts +21 -0
  47. package/dist/chat/components/ComparisonTable.d.ts +66 -0
  48. package/dist/chat/components/ConsultingStylePicker.d.ts +40 -0
  49. package/dist/chat/components/FloatingComparisonButton.d.ts +7 -0
  50. package/dist/chat/components/FloatingLauncher.d.ts +79 -0
  51. package/dist/chat/components/GroundingReviewCard.d.ts +11 -0
  52. package/dist/chat/components/HandoffNotice.d.ts +9 -0
  53. package/dist/chat/components/KvkkBanner.d.ts +6 -0
  54. package/dist/chat/components/Launcher.d.ts +28 -0
  55. package/dist/chat/components/PanelRestoreCard.d.ts +4 -0
  56. package/dist/chat/components/PanelTopBar.d.ts +32 -0
  57. package/dist/chat/components/PhotoAnalysisCard.d.ts +27 -0
  58. package/dist/chat/components/ProductSummaryCard.d.ts +12 -0
  59. package/dist/chat/components/ProsAndCons.d.ts +8 -0
  60. package/dist/chat/components/ReviewHighlights.d.ts +16 -0
  61. package/dist/chat/components/actionClassifier.d.ts +12 -0
  62. package/dist/chat/components/product-price-layout.d.ts +17 -0
  63. package/dist/chat/components/productMentionLinker.d.ts +26 -0
  64. package/dist/chat/components/renderUISpec.d.ts +15 -0
  65. package/dist/chat/components/typewriter.d.ts +24 -0
  66. package/dist/chat/extendedModeManager.d.ts +32 -0
  67. package/dist/chat/features/beauty-consulting/consulting-grid.d.ts +38 -0
  68. package/dist/chat/features/beauty-consulting/drawer-extensions.d.ts +22 -0
  69. package/dist/chat/features/beauty-consulting/mode-controller.d.ts +59 -0
  70. package/dist/chat/features/beauty-consulting/registry.d.ts +9 -0
  71. package/dist/chat/features/beauty-consulting/stream-handler.d.ts +45 -0
  72. package/dist/chat/history-storage.d.ts +85 -0
  73. package/dist/chat/index.d.ts +6 -0
  74. package/dist/chat/kvkk.d.ts +20 -0
  75. package/dist/chat/locales/en.d.ts +2 -0
  76. package/dist/chat/locales/index.d.ts +5 -0
  77. package/dist/chat/locales/tr.d.ts +2 -0
  78. package/dist/chat/panel-manager.d.ts +142 -0
  79. package/dist/chat/runtime.d.ts +416 -0
  80. package/dist/chat/session-persistence.d.ts +73 -0
  81. package/dist/chat/stream-error-display.d.ts +6 -0
  82. package/dist/chat/types.d.ts +547 -0
  83. package/dist/chat/utils/chat-presentation-debug.d.ts +18 -0
  84. package/dist/chat/utils/get-chat-scroll-element.d.ts +10 -0
  85. package/dist/chat/utils/ui.d.ts +10 -0
  86. package/dist/chat-runtime.js +1 -1
  87. package/dist/chat.iife.js +12 -12
  88. package/dist/chat.js +1 -1
  89. package/dist/common/action-router.d.ts +26 -0
  90. package/dist/common/api-paths.d.ts +23 -0
  91. package/dist/common/client.d.ts +27 -0
  92. package/dist/common/communication-bridge.d.ts +51 -0
  93. package/dist/common/config-constants.d.ts +1 -0
  94. package/dist/common/config-schema.d.ts +54 -0
  95. package/dist/common/connection-warning.d.ts +8 -0
  96. package/dist/common/consulting-sources.d.ts +8 -0
  97. package/dist/common/context.d.ts +64 -0
  98. package/dist/common/css-escape.d.ts +1 -0
  99. package/dist/common/customization-factories.d.ts +59 -0
  100. package/dist/common/debug.d.ts +13 -0
  101. package/dist/common/events.d.ts +55 -0
  102. package/dist/common/fastIntent.d.ts +1 -0
  103. package/dist/common/find-similar-payload.d.ts +3 -0
  104. package/dist/common/ga-datalayer.d.ts +80 -0
  105. package/dist/common/global-error-toast.d.ts +6 -0
  106. package/dist/common/index.d.ts +47 -0
  107. package/dist/common/indexed-db.d.ts +89 -0
  108. package/dist/common/locale.d.ts +1 -0
  109. package/dist/common/native-webview.d.ts +60 -0
  110. package/dist/common/navigation.d.ts +1 -0
  111. package/dist/common/overlay.d.ts +172 -0
  112. package/dist/common/page-detect.d.ts +36 -0
  113. package/dist/common/pill-launcher.d.ts +51 -0
  114. package/dist/common/preflight.d.ts +13 -0
  115. package/dist/common/price-formatter.d.ts +35 -0
  116. package/dist/common/product-utils.d.ts +35 -0
  117. package/dist/common/protocol-adapter.d.ts +108 -0
  118. package/dist/common/renderer/dom.d.ts +3 -0
  119. package/dist/common/renderer/index.d.ts +4 -0
  120. package/dist/common/renderer/overrides.d.ts +23 -0
  121. package/dist/common/renderer/registry.d.ts +2 -0
  122. package/dist/common/renderer/types.d.ts +19 -0
  123. package/dist/common/safe-html.d.ts +22 -0
  124. package/dist/common/sdk-version.d.ts +3 -0
  125. package/dist/common/streaming.d.ts +52 -0
  126. package/dist/common/suggested-search-keywords.d.ts +18 -0
  127. package/dist/common/theme-utils.d.ts +15 -0
  128. package/dist/common/transport.d.ts +75 -0
  129. package/dist/common/tts-player.d.ts +13 -0
  130. package/dist/common/types.d.ts +379 -0
  131. package/dist/common/ui-theme.d.ts +9 -0
  132. package/dist/common/uuidv7.d.ts +7 -0
  133. package/dist/common/voice-input.d.ts +74 -0
  134. package/dist/common/widget-base.d.ts +82 -0
  135. package/dist/{common-KpJP1YwP.js → common-BydCGBNn.js} +90 -139
  136. package/dist/common.js +41 -41
  137. package/dist/{connection-warning-B5T_1oBn.js → connection-warning-Pbvk3J8k.js} +1 -1
  138. package/dist/{fastIntent--Ukm2nOh.js → fastIntent-CkYN2UOl.js} +199 -137
  139. package/dist/index.d.ts +25 -0
  140. package/dist/index.js +50 -50
  141. package/dist/native/index.d.ts +2 -0
  142. package/dist/{native-webview-qfjm4SHx.js → native-webview-JDC1vtde.js} +1 -1
  143. package/dist/native.iife.js +14 -14
  144. package/dist/native.js +1 -1
  145. package/dist/{overlay-CP5A0Hhf.js → overlay-BetAvpVZ.js} +19 -19
  146. package/dist/overlay.d.ts +4 -0
  147. package/dist/overlay.js +1 -1
  148. package/dist/qna/api.d.ts +23 -0
  149. package/dist/qna/catalog.d.ts +60 -0
  150. package/dist/qna/components/ButtonRow.d.ts +15 -0
  151. package/dist/qna/components/TextInput.d.ts +11 -0
  152. package/dist/qna/components/renderUISpec.d.ts +7 -0
  153. package/dist/qna/index.d.ts +3 -0
  154. package/dist/qna/locales/en.d.ts +2 -0
  155. package/dist/qna/locales/index.d.ts +4 -0
  156. package/dist/qna/locales/tr.d.ts +2 -0
  157. package/dist/qna/normalize-ui-specs.d.ts +15 -0
  158. package/dist/qna/runtime.d.ts +73 -0
  159. package/dist/qna/types.d.ts +98 -0
  160. package/dist/qna-runtime.js +1 -1
  161. package/dist/qna.iife.js +1 -1
  162. package/dist/qna.js +1 -1
  163. package/dist/{runtime-BPyXOyyp.js → runtime-DbZO1qG5.js} +3 -3
  164. package/dist/{runtime-G3idwfkM.js → runtime-OpNoB3cu.js} +894 -853
  165. package/dist/{runtime-C3yOvNFK.js → runtime-iCLkUjI3.js} +3 -3
  166. package/dist/simbut/index.d.ts +31 -0
  167. package/dist/simbut/locales.d.ts +3 -0
  168. package/dist/simbut/types.d.ts +43 -0
  169. package/dist/{simbut-CiknJI6-.js → simbut-FyXolmZY.js} +1 -1
  170. package/dist/simbut.iife.js +1 -1
  171. package/dist/simbut.js +1 -1
  172. package/dist/simrel/api.d.ts +25 -0
  173. package/dist/simrel/catalog.d.ts +77 -0
  174. package/dist/simrel/components/GroupTabs.d.ts +24 -0
  175. package/dist/simrel/components/ProductCard.d.ts +19 -0
  176. package/dist/simrel/components/ProductGrid.d.ts +17 -0
  177. package/dist/simrel/components/renderUISpec.d.ts +7 -0
  178. package/dist/simrel/index.d.ts +5 -0
  179. package/dist/simrel/locales/en.d.ts +2 -0
  180. package/dist/simrel/locales/index.d.ts +4 -0
  181. package/dist/simrel/locales/tr.d.ts +2 -0
  182. package/dist/simrel/renderers/default.d.ts +41 -0
  183. package/dist/simrel/runtime.d.ts +68 -0
  184. package/dist/simrel/types.d.ts +145 -0
  185. package/dist/{simrel-C1YN71aW.js → simrel-CbLe5OAr.js} +1 -1
  186. package/dist/simrel-runtime.js +1 -1
  187. package/dist/simrel.iife.js +1 -1
  188. package/dist/simrel.js +2 -2
  189. package/dist/{widget-base-UmvgIqDk.js → widget-base-COP8QwU3.js} +1 -1
  190. package/package.json +20 -6
@@ -1,9 +1,9 @@
1
- import { a as x, d as L, h as j, i as q, p as F, r as I, t as N } from "./api-paths-CwzwbgQZ.js";
1
+ import { a as x, d as L, h as j, i as q, p as F, r as I, t as N } from "./api-paths-DJFF9RuZ.js";
2
2
  import { A as z, E as S, N as D, a as k, l as H, v as $ } from "./context-BBuSsXZ9.js";
3
- import { o as W, t as J } from "./widget-base-UmvgIqDk.js";
3
+ import { o as W, t as J } from "./widget-base-COP8QwU3.js";
4
4
  import { t as K } from "./locale-CfqNifrU.js";
5
5
  import { a as Q, n as V, r as Y, t as A } from "./price-formatter-xI3g9Cd4.js";
6
- import { n as X } from "./connection-warning-B5T_1oBn.js";
6
+ import { n as X } from "./connection-warning-Pbvk3J8k.js";
7
7
  function R(e) {
8
8
  const t = [];
9
9
  for (const n of Object.values(e)) if (n.type === "ProductCard" && n.props) {
@@ -0,0 +1,31 @@
1
+ /**
2
+ * SimBut — a "Find Similar" button for the top-right of a PDP product image.
3
+ * On click, it sends a `findSimilar` action through chat using the same protocol as the panel pill.
4
+ *
5
+ * Layout: the button is absolutely positioned in the mount corner and does not take layout space.
6
+ * The mount should be a product image wrapper with `position: relative | absolute | fixed`;
7
+ * static mounts are promoted to `relative` so the host layout and image size are not affected.
8
+ */
9
+ import { BaseWidget } from '../common/widget-base.js';
10
+ import type { PageContext } from '../common/types.js';
11
+ import type { GengageChat } from '../chat/index.js';
12
+ import type { SimButWidgetConfig } from './types.js';
13
+ import './simbut.css';
14
+ export declare class GengageSimBut extends BaseWidget<SimButWidgetConfig> {
15
+ private _button;
16
+ private _inlineFrame;
17
+ private _label;
18
+ protected onInit(config: SimButWidgetConfig): Promise<void>;
19
+ private _createInlineCard;
20
+ protected onUpdate(_context: Partial<PageContext>): void;
21
+ hide(): void;
22
+ show(): void;
23
+ protected _cleanupRoot(): void;
24
+ protected onShow(): void;
25
+ protected onHide(): void;
26
+ protected onDestroy(): void;
27
+ /** Optional hook for wiring overlay chat after initialization. */
28
+ setChat(chat: GengageChat | null): void;
29
+ }
30
+ export declare function createSimButWidget(): GengageSimBut;
31
+ export type { SimButWidgetConfig, SimButI18n, SimButInlineCardConfig, SimButLayout } from './types.js';
@@ -0,0 +1,3 @@
1
+ import type { SimButI18n } from './types.js';
2
+ export declare const SIMBUT_I18N_TR: SimButI18n;
3
+ export declare const SIMBUT_I18N_EN: SimButI18n;
@@ -0,0 +1,43 @@
1
+ import type { BaseWidgetConfig } from '../common/types.js';
2
+ import type { GengageChat } from '../chat/index.js';
3
+ export interface SimButI18n {
4
+ findSimilarLabel: string;
5
+ }
6
+ export type SimButLayout = 'overlay' | 'inline-card';
7
+ export interface SimButInlineCardConfig {
8
+ title?: string;
9
+ description?: string;
10
+ imageUrl?: string;
11
+ imageAlt?: string;
12
+ }
13
+ export interface SimButWidgetConfig extends BaseWidgetConfig {
14
+ /**
15
+ * Product image element, or its `position: relative` wrapper.
16
+ * The button is absolutely positioned inside this element and does not take layout space.
17
+ */
18
+ mountTarget: HTMLElement | string;
19
+ /** Visual layout. Defaults to the existing product-image overlay pill. */
20
+ layout?: SimButLayout;
21
+ /** Content used by `layout: 'inline-card'`. Ignored for overlay layout. */
22
+ inlineCard?: SimButInlineCardConfig;
23
+ /**
24
+ * Product SKU. Falls back to `pageContext.sku`, including overlay context updates.
25
+ */
26
+ sku?: string;
27
+ /** Optional product image URL passed to custom `onFindSimilar`; chat actions use SKU when available. */
28
+ imageUrl?: string;
29
+ /**
30
+ * Chat instance used to open chat and send `findSimilar`. `initOverlayWidgets` wires this automatically.
31
+ */
32
+ chat?: GengageChat | null;
33
+ /**
34
+ * Overrides the default click behavior, for example for a custom integration.
35
+ * When defined, `chat` is not used.
36
+ */
37
+ onFindSimilar?: (detail: {
38
+ sku: string;
39
+ imageUrl?: string;
40
+ }) => void;
41
+ locale?: string;
42
+ i18n?: Partial<SimButI18n>;
43
+ }
@@ -1,5 +1,5 @@
1
1
  import { A as m, D as h, _ as u, j as f, v as p } from "./context-BBuSsXZ9.js";
2
- import { t as b } from "./widget-base-UmvgIqDk.js";
2
+ import { t as b } from "./widget-base-COP8QwU3.js";
3
3
  import { t as y } from "./locale-CfqNifrU.js";
4
4
  var g = { findSimilarLabel: "Benzerlerini Bul" }, _ = { findSimilarLabel: "Find Similar" };
5
5
  function S(t, n) {
@@ -44,4 +44,4 @@
44
44
  transform: translateY(0);
45
45
  }
46
46
  }
47
- `,document.head.appendChild(e)}var f=null;function Y(){if(f!==null)return f;try{f=localStorage.getItem("gengage:debug")==="1"}catch{f=!1}return f}function S(e,t,i){if(!Y())return;const n=[`[gengage:${e}]`,t];i!==void 0&&n.push(i),console.debug(...n)}var j=("0.5.7".trim(),"0.5.7".trim()),J=("iife-build".trim(),"iife-build".trim());function K(){if(typeof window>"u")return;const e=window;e.__gengageSdkRuntimeInfoLogged||(e.__gengageSdkRuntimeInfoLogged=!0,console.info(`[gengage] @gengage/assistant-fe v${j} (${J})`))}var Q=class{constructor(){this.isVisible=!1,this.isInitialised=!1,this._handlers=new Map,this._cleanups=[],this._ownsRoot=!1,this._destroying=!1}async init(e){if(this.isInitialised){console.warn("[gengage] Widget already initialised. Call update() instead.");return}const t=U(e.theme);K(),this.config={...e,theme:t,session:N(e.session)},this.root=this._resolveMount(e.mountTarget),this._applyTheme(t),O();const i=x("gengage:context:update",n=>this.update(n));this._cleanups.push(i),S("lifecycle",`${this.constructor.name}.init`,{accountId:e.accountId,sku:e.pageContext?.sku});try{await this.onInit(this.config)}catch(n){throw this.destroy(),n}this._destroying||(this.isInitialised=!0,S("lifecycle",`${this.constructor.name} ready`),this.emit("ready"))}update(e){this.isInitialised&&(this.config.pageContext?this.config={...this.config,pageContext:{...this.config.pageContext,...e}}:e.pageType!==void 0&&(this.config={...this.config,pageContext:e}),this.onUpdate(e),this.emit("context-update",this.config.pageContext))}show(){this.isVisible||(this.isVisible=!0,this.root.style.display="",this.onShow(),this.emit("show"))}hide(){this.isVisible&&(this.isVisible=!1,this.root.style.display="none",this.onHide(),this.emit("hide"))}destroy(){this._destroying||(this._destroying=!0,this.emit("destroy"),this._cleanups.forEach(e=>e()),this._cleanups.length=0,this._handlers.clear(),this.onDestroy(),this._cleanupRoot(),this.isInitialised=!1)}_cleanupRoot(){this._ownsRoot?this.root.remove():this.root.innerHTML=""}on(e,t){return this._handlers.has(e)||this._handlers.set(e,new Set),this._handlers.get(e).add(t),()=>this._handlers.get(e)?.delete(t)}emit(e,...t){this._handlers.get(e)?.forEach(i=>i(...t))}addCleanup(e){this._cleanups.push(e)}_resolveMount(e){if(e instanceof HTMLElement)return e;if(typeof e=="string"){const i=document.querySelector(e);if(!i)throw new Error(`[gengage] Mount target not found: "${e}"`);return i}const t=document.createElement("div");return t.dataset.gengageWidget=this.constructor.name.toLowerCase(),document.body.insertBefore(t,document.body.firstChild),this._ownsRoot=!0,t}_applyTheme(e){if(e){for(const[t,i]of Object.entries(e))if(i!==void 0){const n=t.startsWith("--")?t:`--gengage-${X(t)}`;this.root.style.setProperty(n,i)}}}};function X(e){return e.replace(/([A-Z])/g,"-$1").toLowerCase()}function Z(e){const t=e?.trim();return t||"tr"}var C={findSimilarLabel:"Benzerlerini Bul"},ee={findSimilarLabel:"Find Similar"};function te(e,t){return t?.findSimilarLabel?t.findSimilarLabel:(e??"tr").toLowerCase().startsWith("en")?ee.findSimilarLabel:C.findSimilarLabel}function h(e){const t=typeof e.sku=="string"&&e.sku.length>0?e.sku:void 0,i=typeof e.pageContext?.sku=="string"&&e.pageContext.sku.length>0?e.pageContext.sku:void 0;return t??i}var E=class extends Q{constructor(...e){super(...e),this._button=null,this._inlineFrame=null,this._label=C.findSimilarLabel}async onInit(e){this._label=te(e.locale,e.i18n);const t=e.layout??"overlay";this.root.classList.add("gengage-simbut-root"),this.root.classList.toggle("gengage-simbut-root--overlay",t==="overlay"),this.root.classList.toggle("gengage-simbut-root--inline-card",t==="inline-card"),t==="overlay"&&window.getComputedStyle(this.root).position==="static"&&(this.root.style.position="relative");const i=document.createElement("button");i.type="button",i.className="gengage-chat-find-similar-pill",i.lang=Z(e.locale),i.textContent=this._label,this._button=i;const n=()=>{i.disabled=!(h(this.config)&&(this.config.onFindSimilar||this.config.chat))};if(i.addEventListener("click",r=>{r.stopPropagation();const s=h(this.config);if(!s)return;const o=this.config.imageUrl,g=typeof o=="string"&&L(o)?o:void 0;if(F(this._label,"findSimilar"),R(s),this.config.onFindSimilar){this.config.onFindSimilar(g?{sku:s,imageUrl:g}:{sku:s});return}const u=this.config.chat;if(!u)return;const a={title:this._label,type:"findSimilar",payload:{sku:s}};u.openWithAction(a,{sku:s})}),t==="inline-card"){const r=this._createInlineCard(e,i);this._inlineFrame=r,this.root.appendChild(r)}else this.root.appendChild(i);n(),k("simbut")}_createInlineCard(e,t){const i=e.inlineCard,n=typeof i?.title=="string"?i.title.trim():"",r=typeof i?.description=="string"?i.description.trim():"",s=typeof i?.imageUrl=="string"?i.imageUrl.trim():"",o=document.createElement("section");o.className="gengage-simbut-inline-card",o.dataset.gengagePart="simbut-inline-card";const g=document.createElement("div");if(g.className="gengage-simbut-inline-copy",g.dataset.gengagePart="simbut-inline-copy",n){const a=document.createElement("h4");a.className="gengage-simbut-inline-title",a.dataset.gengagePart="simbut-inline-title",a.textContent=n,g.appendChild(a)}if(r){const a=document.createElement("p");a.className="gengage-simbut-inline-description",a.dataset.gengagePart="simbut-inline-description",a.textContent=r,g.appendChild(a)}g.children.length>0&&o.appendChild(g);const u=document.createElement("div");if(u.className="gengage-simbut-inline-action",u.dataset.gengagePart="simbut-inline-action",u.appendChild(t),o.appendChild(u),s&&I(s)){const a=document.createElement("img");a.className="gengage-simbut-inline-image",a.dataset.gengagePart="simbut-inline-image",a.src=s,a.alt=typeof i?.imageAlt=="string"?i.imageAlt:"",a.loading="lazy",a.addEventListener("error",()=>{a.style.display="none"},{once:!0}),o.appendChild(a)}return o}onUpdate(e){if(!this._button)return;const t=!!h(this.config)&&(!!this.config.onFindSimilar||!!this.config.chat);this._button.disabled=!t}hide(){this.isVisible&&(this.isVisible=!1,this._inlineFrame&&(this._inlineFrame.style.display="none"),this._button&&(this._button.style.display="none"),this.onHide(),this.emit("hide"))}show(){this.isVisible||(this.isVisible=!0,this._inlineFrame&&(this._inlineFrame.style.display=""),this._button&&(this._button.style.display=""),this.onShow(),this.emit("show"))}_cleanupRoot(){}onShow(){}onHide(){}onDestroy(){this._inlineFrame?.remove(),this._inlineFrame=null,this._button?.remove(),this._button=null}setChat(e){if(this.config.chat=e,this._button){const t=!!h(this.config)&&(!!this.config.onFindSimilar||!!this.config.chat);this._button.disabled=!t}}};function ie(){return new E}m.GengageSimBut=E,m.createSimButWidget=ie})(this.Gengage=this.Gengage||{});
47
+ `,document.head.appendChild(e)}var f=null;function Y(){if(f!==null)return f;try{f=localStorage.getItem("gengage:debug")==="1"}catch{f=!1}return f}function S(e,t,i){if(!Y())return;const n=[`[gengage:${e}]`,t];i!==void 0&&n.push(i),console.debug(...n)}var j=("0.6.0".trim(),"0.6.0".trim()),J=("iife-build".trim(),"iife-build".trim());function K(){if(typeof window>"u")return;const e=window;e.__gengageSdkRuntimeInfoLogged||(e.__gengageSdkRuntimeInfoLogged=!0,console.info(`[gengage] @gengage/assistant-fe v${j} (${J})`))}var Q=class{constructor(){this.isVisible=!1,this.isInitialised=!1,this._handlers=new Map,this._cleanups=[],this._ownsRoot=!1,this._destroying=!1}async init(e){if(this.isInitialised){console.warn("[gengage] Widget already initialised. Call update() instead.");return}const t=U(e.theme);K(),this.config={...e,theme:t,session:N(e.session)},this.root=this._resolveMount(e.mountTarget),this._applyTheme(t),O();const i=x("gengage:context:update",n=>this.update(n));this._cleanups.push(i),S("lifecycle",`${this.constructor.name}.init`,{accountId:e.accountId,sku:e.pageContext?.sku});try{await this.onInit(this.config)}catch(n){throw this.destroy(),n}this._destroying||(this.isInitialised=!0,S("lifecycle",`${this.constructor.name} ready`),this.emit("ready"))}update(e){this.isInitialised&&(this.config.pageContext?this.config={...this.config,pageContext:{...this.config.pageContext,...e}}:e.pageType!==void 0&&(this.config={...this.config,pageContext:e}),this.onUpdate(e),this.emit("context-update",this.config.pageContext))}show(){this.isVisible||(this.isVisible=!0,this.root.style.display="",this.onShow(),this.emit("show"))}hide(){this.isVisible&&(this.isVisible=!1,this.root.style.display="none",this.onHide(),this.emit("hide"))}destroy(){this._destroying||(this._destroying=!0,this.emit("destroy"),this._cleanups.forEach(e=>e()),this._cleanups.length=0,this._handlers.clear(),this.onDestroy(),this._cleanupRoot(),this.isInitialised=!1)}_cleanupRoot(){this._ownsRoot?this.root.remove():this.root.innerHTML=""}on(e,t){return this._handlers.has(e)||this._handlers.set(e,new Set),this._handlers.get(e).add(t),()=>this._handlers.get(e)?.delete(t)}emit(e,...t){this._handlers.get(e)?.forEach(i=>i(...t))}addCleanup(e){this._cleanups.push(e)}_resolveMount(e){if(e instanceof HTMLElement)return e;if(typeof e=="string"){const i=document.querySelector(e);if(!i)throw new Error(`[gengage] Mount target not found: "${e}"`);return i}const t=document.createElement("div");return t.dataset.gengageWidget=this.constructor.name.toLowerCase(),document.body.insertBefore(t,document.body.firstChild),this._ownsRoot=!0,t}_applyTheme(e){if(e){for(const[t,i]of Object.entries(e))if(i!==void 0){const n=t.startsWith("--")?t:`--gengage-${X(t)}`;this.root.style.setProperty(n,i)}}}};function X(e){return e.replace(/([A-Z])/g,"-$1").toLowerCase()}function Z(e){const t=e?.trim();return t||"tr"}var C={findSimilarLabel:"Benzerlerini Bul"},ee={findSimilarLabel:"Find Similar"};function te(e,t){return t?.findSimilarLabel?t.findSimilarLabel:(e??"tr").toLowerCase().startsWith("en")?ee.findSimilarLabel:C.findSimilarLabel}function h(e){const t=typeof e.sku=="string"&&e.sku.length>0?e.sku:void 0,i=typeof e.pageContext?.sku=="string"&&e.pageContext.sku.length>0?e.pageContext.sku:void 0;return t??i}var E=class extends Q{constructor(...e){super(...e),this._button=null,this._inlineFrame=null,this._label=C.findSimilarLabel}async onInit(e){this._label=te(e.locale,e.i18n);const t=e.layout??"overlay";this.root.classList.add("gengage-simbut-root"),this.root.classList.toggle("gengage-simbut-root--overlay",t==="overlay"),this.root.classList.toggle("gengage-simbut-root--inline-card",t==="inline-card"),t==="overlay"&&window.getComputedStyle(this.root).position==="static"&&(this.root.style.position="relative");const i=document.createElement("button");i.type="button",i.className="gengage-chat-find-similar-pill",i.lang=Z(e.locale),i.textContent=this._label,this._button=i;const n=()=>{i.disabled=!(h(this.config)&&(this.config.onFindSimilar||this.config.chat))};if(i.addEventListener("click",r=>{r.stopPropagation();const s=h(this.config);if(!s)return;const o=this.config.imageUrl,g=typeof o=="string"&&L(o)?o:void 0;if(F(this._label,"findSimilar"),R(s),this.config.onFindSimilar){this.config.onFindSimilar(g?{sku:s,imageUrl:g}:{sku:s});return}const u=this.config.chat;if(!u)return;const a={title:this._label,type:"findSimilar",payload:{sku:s}};u.openWithAction(a,{sku:s})}),t==="inline-card"){const r=this._createInlineCard(e,i);this._inlineFrame=r,this.root.appendChild(r)}else this.root.appendChild(i);n(),k("simbut")}_createInlineCard(e,t){const i=e.inlineCard,n=typeof i?.title=="string"?i.title.trim():"",r=typeof i?.description=="string"?i.description.trim():"",s=typeof i?.imageUrl=="string"?i.imageUrl.trim():"",o=document.createElement("section");o.className="gengage-simbut-inline-card",o.dataset.gengagePart="simbut-inline-card";const g=document.createElement("div");if(g.className="gengage-simbut-inline-copy",g.dataset.gengagePart="simbut-inline-copy",n){const a=document.createElement("h4");a.className="gengage-simbut-inline-title",a.dataset.gengagePart="simbut-inline-title",a.textContent=n,g.appendChild(a)}if(r){const a=document.createElement("p");a.className="gengage-simbut-inline-description",a.dataset.gengagePart="simbut-inline-description",a.textContent=r,g.appendChild(a)}g.children.length>0&&o.appendChild(g);const u=document.createElement("div");if(u.className="gengage-simbut-inline-action",u.dataset.gengagePart="simbut-inline-action",u.appendChild(t),o.appendChild(u),s&&I(s)){const a=document.createElement("img");a.className="gengage-simbut-inline-image",a.dataset.gengagePart="simbut-inline-image",a.src=s,a.alt=typeof i?.imageAlt=="string"?i.imageAlt:"",a.loading="lazy",a.addEventListener("error",()=>{a.style.display="none"},{once:!0}),o.appendChild(a)}return o}onUpdate(e){if(!this._button)return;const t=!!h(this.config)&&(!!this.config.onFindSimilar||!!this.config.chat);this._button.disabled=!t}hide(){this.isVisible&&(this.isVisible=!1,this._inlineFrame&&(this._inlineFrame.style.display="none"),this._button&&(this._button.style.display="none"),this.onHide(),this.emit("hide"))}show(){this.isVisible||(this.isVisible=!0,this._inlineFrame&&(this._inlineFrame.style.display=""),this._button&&(this._button.style.display=""),this.onShow(),this.emit("show"))}_cleanupRoot(){}onShow(){}onHide(){}onDestroy(){this._inlineFrame?.remove(),this._inlineFrame=null,this._button?.remove(),this._button=null}setChat(e){if(this.config.chat=e,this._button){const t=!!h(this.config)&&(!!this.config.onFindSimilar||!!this.config.chat);this._button.disabled=!t}}};function ie(){return new E}m.GengageSimBut=E,m.createSimButWidget=ie})(this.Gengage=this.Gengage||{});
package/dist/simbut.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as e, t as a } from "./simbut-CiknJI6-.js";
1
+ import { n as e, t as a } from "./simbut-FyXolmZY.js";
2
2
  export {
3
3
  a as GengageSimBut,
4
4
  e as createSimButWidget
@@ -0,0 +1,25 @@
1
+ import type { NormalizedProduct } from '../common/protocol-adapter.js';
2
+ import type { ChatTransportConfig } from '../common/api-paths.js';
3
+ export interface SimilarProductsRequest {
4
+ account_id: string;
5
+ session_id: string;
6
+ correlation_id: string;
7
+ sku: string;
8
+ domain?: string;
9
+ limit?: number;
10
+ output_language?: string;
11
+ }
12
+ export interface ProductGroupingsRequest {
13
+ account_id: string;
14
+ session_id: string;
15
+ correlation_id: string;
16
+ skus: string[];
17
+ output_language?: string;
18
+ }
19
+ export interface ProductGroup {
20
+ name: string;
21
+ highlight?: string;
22
+ products: NormalizedProduct[];
23
+ }
24
+ export declare function fetchSimilarProducts(request: SimilarProductsRequest, transport: ChatTransportConfig, signal?: AbortSignal): Promise<NormalizedProduct[]>;
25
+ export declare function fetchProductGroupings(request: ProductGroupingsRequest, transport: ChatTransportConfig, signal?: AbortSignal): Promise<ProductGroup[]>;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Similar Products (SimRel) widget — json-render catalog definition.
3
+ *
4
+ * Backend endpoints:
5
+ * POST /chat/similar_products — primary product list
6
+ * POST /chat/product_groupings — grouped/tabbed view
7
+ *
8
+ * The backend streams NDJSON events. `ui_spec` events reference
9
+ * component names defined below. Implementations live in ./registry.
10
+ */
11
+ import { z } from 'zod';
12
+ export declare const simRelCatalog: {
13
+ readonly components: {
14
+ readonly ProductGrid: {
15
+ readonly schema: z.ZodObject<{
16
+ layout: z.ZodOptional<z.ZodEnum<{
17
+ grid: "grid";
18
+ carousel: "carousel";
19
+ }>>;
20
+ columns: z.ZodOptional<z.ZodNumber>;
21
+ }, z.core.$strip>;
22
+ readonly description: "Outer grid or carousel container for similar products.";
23
+ };
24
+ readonly ProductCard: {
25
+ readonly schema: z.ZodObject<{
26
+ product: z.ZodObject<{
27
+ sku: z.ZodString;
28
+ name: z.ZodString;
29
+ imageUrl: z.ZodOptional<z.ZodString>;
30
+ price: z.ZodOptional<z.ZodString>;
31
+ originalPrice: z.ZodOptional<z.ZodString>;
32
+ discountPercent: z.ZodOptional<z.ZodNumber>;
33
+ url: z.ZodString;
34
+ brand: z.ZodOptional<z.ZodString>;
35
+ rating: z.ZodOptional<z.ZodNumber>;
36
+ reviewCount: z.ZodOptional<z.ZodNumber>;
37
+ }, z.core.$strip>;
38
+ index: z.ZodNumber;
39
+ discountType: z.ZodOptional<z.ZodEnum<{
40
+ inline: "inline";
41
+ "strike-through": "strike-through";
42
+ badge: "badge";
43
+ }>>;
44
+ }, z.core.$strip>;
45
+ readonly description: "A single product card with image, title, price, and actions.";
46
+ };
47
+ readonly AddToCartButton: {
48
+ readonly schema: z.ZodObject<{
49
+ sku: z.ZodString;
50
+ label: z.ZodOptional<z.ZodString>;
51
+ cartCode: z.ZodString;
52
+ }, z.core.$strip>;
53
+ readonly description: "Add-to-cart CTA rendered inside or below a product card.";
54
+ };
55
+ readonly QuickActions: {
56
+ readonly schema: z.ZodObject<{
57
+ actions: z.ZodArray<z.ZodObject<{
58
+ label: z.ZodString;
59
+ action: z.ZodObject<{
60
+ title: z.ZodString;
61
+ type: z.ZodString;
62
+ payload: z.ZodOptional<z.ZodUnknown>;
63
+ }, z.core.$strip>;
64
+ }, z.core.$strip>>;
65
+ }, z.core.$strip>;
66
+ readonly description: "A row of quick-action buttons below product info.";
67
+ };
68
+ readonly EmptyState: {
69
+ readonly schema: z.ZodObject<{
70
+ message: z.ZodOptional<z.ZodString>;
71
+ }, z.core.$strip>;
72
+ readonly description: "Empty state shown when no similar products are available.";
73
+ };
74
+ };
75
+ };
76
+ export type SimRelCatalog = typeof simRelCatalog;
77
+ export type SimRelComponentName = keyof SimRelCatalog['components'];
@@ -0,0 +1,24 @@
1
+ import type { NormalizedProduct } from '../../common/protocol-adapter.js';
2
+ import type { ProductGroup } from '../api.js';
3
+ import type { SimRelI18n } from '../types.js';
4
+ export interface GroupTabsOptions {
5
+ groups: ProductGroup[];
6
+ discountType?: 'strike-through' | 'badge' | 'inline';
7
+ onClick: (product: NormalizedProduct) => void;
8
+ onAddToCart: (params: {
9
+ sku: string;
10
+ quantity: number;
11
+ cartCode: string;
12
+ }) => void;
13
+ renderCard?: (product: NormalizedProduct, index: number) => string;
14
+ renderCardElement?: (product: NormalizedProduct, index: number) => HTMLElement | null;
15
+ i18n?: SimRelI18n;
16
+ /** ProductGrid `columns`: number of cards per desktop row. */
17
+ columns?: number;
18
+ /** User changed grouping tab (click or keyboard). */
19
+ onGroupingActivate?: (detail: {
20
+ grouping_label: string;
21
+ grouping_index: number;
22
+ }) => void;
23
+ }
24
+ export declare function renderGroupTabs(options: GroupTabsOptions): HTMLElement;
@@ -0,0 +1,19 @@
1
+ import type { NormalizedProduct } from '../../common/protocol-adapter.js';
2
+ import type { SimRelI18n } from '../types.js';
3
+ import type { PriceFormatConfig } from '../../common/price-formatter.js';
4
+ export interface ProductCardOptions {
5
+ product: NormalizedProduct;
6
+ index: number;
7
+ discountType?: 'strike-through' | 'badge' | 'inline';
8
+ onClick: (product: NormalizedProduct) => void;
9
+ onAddToCart: (params: {
10
+ sku: string;
11
+ quantity: number;
12
+ cartCode: string;
13
+ }) => void;
14
+ renderCard?: (product: NormalizedProduct, index: number) => string;
15
+ renderCardElement?: (product: NormalizedProduct, index: number) => HTMLElement | null;
16
+ i18n?: SimRelI18n;
17
+ pricing?: PriceFormatConfig;
18
+ }
19
+ export declare function renderProductCard(options: ProductCardOptions): HTMLElement;
@@ -0,0 +1,17 @@
1
+ import type { NormalizedProduct } from '../../common/protocol-adapter.js';
2
+ import type { SimRelI18n } from '../types.js';
3
+ export interface ProductGridOptions {
4
+ products: NormalizedProduct[];
5
+ columns?: number;
6
+ discountType?: 'strike-through' | 'badge' | 'inline';
7
+ onClick: (product: NormalizedProduct) => void;
8
+ onAddToCart: (params: {
9
+ sku: string;
10
+ quantity: number;
11
+ cartCode: string;
12
+ }) => void;
13
+ renderCard?: (product: NormalizedProduct, index: number) => string;
14
+ renderCardElement?: (product: NormalizedProduct, index: number) => HTMLElement | null;
15
+ i18n?: SimRelI18n;
16
+ }
17
+ export declare function renderProductGrid(options: ProductGridOptions): HTMLElement;
@@ -0,0 +1,7 @@
1
+ import type { UISpecDomRegistry, UISpecDomUnknownRenderer } from '../../common/renderer/index.js';
2
+ import type { UISpec } from '../../common/types.js';
3
+ import type { SimRelUISpecRenderContext } from '../types.js';
4
+ export type SimRelUISpecRegistry = UISpecDomRegistry<SimRelUISpecRenderContext>;
5
+ export declare const defaultSimRelUnknownUISpecRenderer: UISpecDomUnknownRenderer<SimRelUISpecRenderContext>;
6
+ export declare function createDefaultSimRelUISpecRegistry(): SimRelUISpecRegistry;
7
+ export declare function renderSimRelUISpec(spec: UISpec, context: SimRelUISpecRenderContext, registry?: SimRelUISpecRegistry, unknownRenderer?: UISpecDomUnknownRenderer<SimRelUISpecRenderContext>): HTMLElement;
@@ -0,0 +1,5 @@
1
+ export * from './runtime.js';
2
+ export { createSimRelRenderer } from './renderers/default.js';
3
+ export type { SimRelFieldPath, SimRelRendererFields, SimRelRendererLabels, SimRelRendererMedia, SimRelRendererOptions, } from './renderers/default.js';
4
+ export { simRelCatalog } from './catalog.js';
5
+ export type { SimRelCatalog, SimRelComponentName } from './catalog.js';
@@ -0,0 +1,2 @@
1
+ import type { SimRelI18n } from '../types.js';
2
+ export declare const SIMREL_I18N_EN: SimRelI18n;
@@ -0,0 +1,4 @@
1
+ import type { SimRelI18n } from '../types.js';
2
+ import { SIMREL_I18N_TR } from './tr.js';
3
+ export declare function resolveSimRelLocale(locale?: string): SimRelI18n;
4
+ export { SIMREL_I18N_TR };
@@ -0,0 +1,2 @@
1
+ import type { SimRelI18n } from '../types.js';
2
+ export declare const SIMREL_I18N_TR: SimRelI18n;
@@ -0,0 +1,41 @@
1
+ import type { PriceFormatConfig } from '../../common/price-formatter.js';
2
+ import type { SimilarProduct, SimRelRendererConfig } from '../types.js';
3
+ import './default.css';
4
+ export type SimRelFieldPath = string | readonly string[];
5
+ export interface SimRelRendererLabels {
6
+ cta?: string;
7
+ productInfo?: string;
8
+ customBadgeAlt?: string;
9
+ review?: (count: number) => string;
10
+ imageDot?: (index: number) => string;
11
+ previousPromotion?: string;
12
+ nextPromotion?: string;
13
+ specialPriceBadgeAlt?: string;
14
+ }
15
+ export interface SimRelRendererFields {
16
+ images?: SimRelFieldPath[];
17
+ subtitle?: SimRelFieldPath[];
18
+ promotions?: SimRelFieldPath[];
19
+ warranties?: SimRelFieldPath[];
20
+ productInfoUrl?: SimRelFieldPath[];
21
+ discountReason?: SimRelFieldPath[];
22
+ specialPrice?: SimRelFieldPath[];
23
+ customBadgeFacets?: SimRelFieldPath[];
24
+ customBadgeText?: SimRelFieldPath[];
25
+ customBadgeImageUrl?: SimRelFieldPath[];
26
+ }
27
+ export interface SimRelRendererMedia {
28
+ promotionIconUrl?: string;
29
+ specialPriceBadgeUrl?: string;
30
+ imageUrlTransform?: (url: string, product: SimilarProduct) => string;
31
+ customBadgeImageUrl?: (product: SimilarProduct, labelText: string) => string | null | undefined;
32
+ }
33
+ export interface SimRelRendererOptions {
34
+ labels?: SimRelRendererLabels;
35
+ fields?: SimRelRendererFields;
36
+ media?: SimRelRendererMedia;
37
+ warrantyPromotionPattern?: RegExp;
38
+ specialPricePattern?: RegExp;
39
+ pricing?: PriceFormatConfig | undefined;
40
+ }
41
+ export declare function createSimRelRenderer(options?: SimRelRendererOptions): SimRelRendererConfig;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Similar Products (SimRel) widget — public entry point.
3
+ *
4
+ * Fetches and renders similar / related products for the current SKU.
5
+ * Backend: POST /chat/similar_products + /chat/product_groupings
6
+ */
7
+ import type { PageContext } from '../common/types.js';
8
+ import type { NormalizedProduct } from '../common/protocol-adapter.js';
9
+ import { BaseWidget } from '../common/widget-base.js';
10
+ import type { SimRelWidgetConfig } from './types.js';
11
+ import './components/simrel.css';
12
+ /**
13
+ * Similar / related products widget for product pages.
14
+ * Fetches AI-powered product recommendations and renders them as a scrollable grid.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * import { GengageSimRel, bootstrapSession } from '@gengage/assistant-fe';
19
+ *
20
+ * const simrel = new GengageSimRel();
21
+ * await simrel.init({
22
+ * accountId: 'mystore',
23
+ * middlewareUrl: '<backend service location provided for your Gengage account>',
24
+ * sku: '12345',
25
+ * mountTarget: '#similar-products',
26
+ * session: { sessionId: bootstrapSession() },
27
+ * onAddToCart: ({ sku, quantity }) => cart.add(sku, quantity),
28
+ * });
29
+ * ```
30
+ */
31
+ export declare class GengageSimRel extends BaseWidget<SimRelWidgetConfig> {
32
+ private _abortController;
33
+ private _contentEl;
34
+ private _lastSku;
35
+ /** Number of products returned from the last successful fetch. Used to allow
36
+ * retry when the same SKU previously produced an empty result set. */
37
+ private _lastResultCount;
38
+ private _i18n;
39
+ private _pendingAddToCartKeys;
40
+ init(config: SimRelWidgetConfig): Promise<void>;
41
+ protected onInit(config: SimRelWidgetConfig): Promise<void>;
42
+ protected onUpdate(context: Partial<PageContext>): void;
43
+ protected onShow(): void;
44
+ protected onHide(): void;
45
+ protected onDestroy(): void;
46
+ _handleProductClick(product: NormalizedProduct): void;
47
+ _handleAddToCart(params: {
48
+ sku: string;
49
+ quantity: number;
50
+ cartCode: string;
51
+ }): Promise<void>;
52
+ private _abort;
53
+ private _isSuperseded;
54
+ private _emitSimilarProductsImpression;
55
+ private _resolveRequestTimeoutMs;
56
+ private _fetchAndRender;
57
+ private _clampGridColumns;
58
+ private _resolveI18n;
59
+ private _resolveUISpecRegistry;
60
+ private _buildRenderContext;
61
+ private _renderUISpec;
62
+ private _buildProductsSpec;
63
+ private _buildGroupsSpec;
64
+ }
65
+ export declare function createSimRelWidget(): GengageSimRel;
66
+ export type { SimRelWidgetConfig, SimilarProduct, SimRelUIComponents, SimRelI18n, SimRelUISpecRenderContext, SimRelRendererConfig, } from './types.js';
67
+ export { renderSimRelUISpec, createDefaultSimRelUISpecRegistry, defaultSimRelUnknownUISpecRenderer, } from './components/renderUISpec.js';
68
+ export type { SimRelUISpecRegistry } from './components/renderUISpec.js';
@@ -0,0 +1,145 @@
1
+ import type { AddToCartHandlerResult, AddToCartParams, BaseWidgetConfig, ActionPayload } from '../common/types.js';
2
+ import type { UISpecRendererOverrides } from '../common/renderer/index.js';
3
+ export interface SimRelWidgetConfig extends BaseWidgetConfig {
4
+ /** Product SKU to find similar items for. Required. */
5
+ sku: string;
6
+ /** Where to render the product grid. Required. */
7
+ mountTarget: HTMLElement | string;
8
+ /** Called when "Add to cart" is tapped on a product card. */
9
+ onAddToCart?: (params: AddToCartParams) => AddToCartHandlerResult;
10
+ /**
11
+ * Called when the user taps a product card (navigation intent).
12
+ * Return false to prevent the widget's default navigation.
13
+ */
14
+ onProductClick?: (product: SimilarProduct) => boolean | void;
15
+ /**
16
+ * Called just before navigating to a product page.
17
+ * Use to call window.gengage.chat.saveSession() for cross-page session continuity.
18
+ */
19
+ onProductNavigate?: (url: string, sku: string, sessionId: string | null) => void;
20
+ /**
21
+ * Override the default product card template.
22
+ *
23
+ * ⚠️ XSS WARNING: This function returns a raw HTML string injected into the DOM.
24
+ * You MUST sanitize any user-controlled data (e.g. product names from the API)
25
+ * using DOMPurify or a similar library before returning.
26
+ *
27
+ * Glov/Gengage accepts no responsibility for XSS vulnerabilities introduced
28
+ * by unsafe renderCard implementations.
29
+ */
30
+ renderCard?: (product: SimilarProduct, index: number) => string;
31
+ /**
32
+ * Override the default product card with a full DOM element.
33
+ * Unlike `renderCard` (HTML string), this returns an HTMLElement,
34
+ * allowing interactive elements (event listeners, state, etc.).
35
+ * Takes precedence over `renderCard` when both are provided.
36
+ */
37
+ renderCardElement?: (product: SimilarProduct, index: number) => HTMLElement | null;
38
+ /** Show the first slot as a "special" card (e.g. a promo or bundle). */
39
+ useSpecialCard?: boolean;
40
+ renderSpecialCard?: (product: SimilarProduct) => string | null;
41
+ /** Discount presentation: original-price strike-through, image badge, or muted inline original price. */
42
+ discountType?: 'strike-through' | 'badge' | 'inline';
43
+ /**
44
+ * Number of product cards per desktop row (1-12). Default: 4.
45
+ * Narrow screens (<=768px) keep the horizontally scrollable carousel behavior.
46
+ */
47
+ gridColumns?: number;
48
+ /** Client-side abort cap for similar-products and grouping requests. Defaults to 120 seconds. */
49
+ requestTimeoutMs?: number;
50
+ /**
51
+ * Enables the optional `/chat/product_groupings` enhancement after similar products load.
52
+ * Defaults to true for backward compatibility. Set false for backends without that micro-ability.
53
+ */
54
+ enableProductGroupings?: boolean;
55
+ domain?: string;
56
+ /** Locale key for SDK defaults (for example 'tr', 'en'). */
57
+ locale?: string;
58
+ i18n?: Partial<SimRelI18n>;
59
+ renderer?: SimRelRendererConfig;
60
+ }
61
+ export interface SimilarProduct {
62
+ sku: string;
63
+ name: string;
64
+ imageUrl?: string;
65
+ price?: string;
66
+ originalPrice?: string;
67
+ discountPercent?: number;
68
+ url: string;
69
+ brand?: string;
70
+ rating?: number;
71
+ reviewCount?: number;
72
+ cartCode?: string;
73
+ inStock?: boolean;
74
+ /** Pass-through bag for backend fields not consumed by the SDK. */
75
+ extras?: Record<string, unknown>;
76
+ }
77
+ export interface SimRelI18n {
78
+ similarProductsAriaLabel: string;
79
+ emptyStateMessage: string;
80
+ addToCartButton: string;
81
+ ctaLabel: string;
82
+ outOfStockLabel: string;
83
+ decreaseLabel: string;
84
+ increaseLabel: string;
85
+ /** Inline error message shown when similar products fail to load. */
86
+ errorLoadingMessage: string;
87
+ /** Retry button label shown alongside the error message. */
88
+ retryButtonText: string;
89
+ /**
90
+ * @deprecated Prefer `pricing` config on the widget for locale-aware formatting.
91
+ * Kept for backwards compatibility with existing custom integrations.
92
+ */
93
+ priceSuffix: string;
94
+ scrollTabsLeft?: string;
95
+ scrollTabsRight?: string;
96
+ }
97
+ export interface SimRelUISpecRenderContext {
98
+ onClick: (product: SimilarProduct) => void;
99
+ onAddToCart: (params: AddToCartParams) => AddToCartHandlerResult;
100
+ /** Fires when the shopper selects a grouping tab (not the initial tab mount). */
101
+ onGroupingActivate?: (detail: {
102
+ grouping_label: string;
103
+ grouping_index: number;
104
+ }) => void;
105
+ onAction?: (action: ActionPayload) => void;
106
+ discountType?: 'strike-through' | 'badge' | 'inline';
107
+ renderCard?: (product: SimilarProduct, index: number) => string;
108
+ renderCardElement?: (product: SimilarProduct, index: number) => HTMLElement | null;
109
+ i18n: SimRelI18n;
110
+ pricing?: import('../common/price-formatter.js').PriceFormatConfig;
111
+ /** Used when the ui_spec `ProductGrid` omits `columns` (widget `gridColumns`). */
112
+ gridColumns?: number;
113
+ }
114
+ export type SimRelRendererConfig = UISpecRendererOverrides<SimRelUISpecRenderContext>;
115
+ export interface SimRelUIComponents {
116
+ /** The outer grid/carousel container. */
117
+ ProductGrid: {
118
+ layout?: 'grid' | 'carousel';
119
+ columns?: number;
120
+ };
121
+ /** A single product card in the grid. */
122
+ ProductCard: {
123
+ product: SimilarProduct;
124
+ index: number;
125
+ discountType?: 'strike-through' | 'badge' | 'inline';
126
+ };
127
+ /** Add-to-cart button inside a card. */
128
+ AddToCartButton: {
129
+ sku: string;
130
+ label?: string;
131
+ /** Cart code / variant identifier. */
132
+ cartCode: string;
133
+ };
134
+ /** A "quick action" row of buttons below the product info. */
135
+ QuickActions: {
136
+ actions: Array<{
137
+ label: string;
138
+ action: ActionPayload;
139
+ }>;
140
+ };
141
+ /** Empty state shown when no similar products are found. */
142
+ EmptyState: {
143
+ message?: string;
144
+ };
145
+ }
@@ -1,7 +1,7 @@
1
1
  import { A, j as S } from "./context-BBuSsXZ9.js";
2
2
  import { n as $, t as L } from "./price-formatter-xI3g9Cd4.js";
3
3
  import { a as C, c as f, n as q, o as h, t as k, u as H } from "./schemas-CLo8wCjs.js";
4
- import { o as j } from "./runtime-C3yOvNFK.js";
4
+ import { o as j } from "./runtime-iCLkUjI3.js";
5
5
  var V = {
6
6
  images: [
7
7
  "images",
@@ -1,4 +1,4 @@
1
- import { a, i as r, n as i, r as t, t as S } from "./runtime-C3yOvNFK.js";
1
+ import { a, i as r, n as i, r as t, t as S } from "./runtime-iCLkUjI3.js";
2
2
  export {
3
3
  S as GengageSimRel,
4
4
  t as createDefaultSimRelUISpecRegistry,