@gengage/assistant-fe 0.2.0 → 0.2.2

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 (69) hide show
  1. package/dist/chat/components/Launcher.d.ts +2 -0
  2. package/dist/chat/components/Launcher.d.ts.map +1 -1
  3. package/dist/chat/index.d.ts.map +1 -1
  4. package/dist/chat/panel-manager.d.ts +16 -0
  5. package/dist/chat/panel-manager.d.ts.map +1 -1
  6. package/dist/chat/types.d.ts +6 -0
  7. package/dist/chat/types.d.ts.map +1 -1
  8. package/dist/chat.cjs +1 -1
  9. package/dist/chat.iife.js +8 -8
  10. package/dist/chat.iife.js.map +1 -1
  11. package/dist/chat.js +2 -2
  12. package/dist/common/overlay.d.ts +11 -0
  13. package/dist/common/overlay.d.ts.map +1 -1
  14. package/dist/common/protocol-adapter.d.ts +2 -0
  15. package/dist/common/protocol-adapter.d.ts.map +1 -1
  16. package/dist/common.cjs +1 -1
  17. package/dist/common.js +5 -5
  18. package/dist/index-CB8DgwIv.cjs +13 -0
  19. package/dist/index-CB8DgwIv.cjs.map +1 -0
  20. package/dist/index-CUukV8wH.cjs +2 -0
  21. package/dist/index-CUukV8wH.cjs.map +1 -0
  22. package/dist/{index-C6KDzSjm.js → index-CpLM7vPC.js} +65 -65
  23. package/dist/index-CpLM7vPC.js.map +1 -0
  24. package/dist/{index-RmQRBt6w.js → index-EEUjXgSt.js} +245 -226
  25. package/dist/index-EEUjXgSt.js.map +1 -0
  26. package/dist/index.cjs +1 -1
  27. package/dist/index.js +3 -3
  28. package/dist/native.cjs +1 -1
  29. package/dist/native.iife.js +17 -17
  30. package/dist/native.iife.js.map +1 -1
  31. package/dist/native.js +1 -1
  32. package/dist/qna/index.d.ts.map +1 -1
  33. package/dist/qna/types.d.ts +3 -0
  34. package/dist/qna/types.d.ts.map +1 -1
  35. package/dist/qna.cjs +1 -1
  36. package/dist/qna.cjs.map +1 -1
  37. package/dist/qna.iife.js +15 -15
  38. package/dist/qna.iife.js.map +1 -1
  39. package/dist/qna.js +11 -12
  40. package/dist/qna.js.map +1 -1
  41. package/dist/{schemas-BAEbjFPE.js → schemas-D1Kd4wn8.js} +524 -499
  42. package/dist/schemas-D1Kd4wn8.js.map +1 -0
  43. package/dist/{schemas-DIyHm5pa.cjs → schemas-DOxyUYVA.cjs} +7 -7
  44. package/dist/schemas-DOxyUYVA.cjs.map +1 -0
  45. package/dist/simrel/components/GroupTabs.d.ts +1 -0
  46. package/dist/simrel/components/GroupTabs.d.ts.map +1 -1
  47. package/dist/simrel/components/ProductCard.d.ts +1 -0
  48. package/dist/simrel/components/ProductCard.d.ts.map +1 -1
  49. package/dist/simrel/components/ProductGrid.d.ts +1 -0
  50. package/dist/simrel/components/ProductGrid.d.ts.map +1 -1
  51. package/dist/simrel/components/renderUISpec.d.ts.map +1 -1
  52. package/dist/simrel/index.d.ts.map +1 -1
  53. package/dist/simrel/types.d.ts +10 -0
  54. package/dist/simrel/types.d.ts.map +1 -1
  55. package/dist/simrel.cjs +1 -1
  56. package/dist/simrel.cjs.map +1 -1
  57. package/dist/simrel.iife.js +5 -5
  58. package/dist/simrel.iife.js.map +1 -1
  59. package/dist/simrel.js +171 -165
  60. package/dist/simrel.js.map +1 -1
  61. package/package.json +1 -1
  62. package/dist/index-BA7N_XOO.cjs +0 -2
  63. package/dist/index-BA7N_XOO.cjs.map +0 -1
  64. package/dist/index-C6KDzSjm.js.map +0 -1
  65. package/dist/index-RmQRBt6w.js.map +0 -1
  66. package/dist/index-VgLdYuZV.cjs +0 -13
  67. package/dist/index-VgLdYuZV.cjs.map +0 -1
  68. package/dist/schemas-BAEbjFPE.js.map +0 -1
  69. package/dist/schemas-DIyHm5pa.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"simrel.js","sources":["../src/simrel/api.ts","../src/simrel/components/ProductCard.ts","../src/simrel/components/ProductGrid.ts","../src/simrel/components/GroupTabs.ts","../src/simrel/components/renderUISpec.ts","../src/simrel/locales/tr.ts","../src/simrel/locales/en.ts","../src/simrel/locales/index.ts","../src/simrel/catalog.ts","../src/simrel/index.ts"],"sourcesContent":["import { buildChatEndpointUrl } from '../common/api-paths.js';\nimport { consumeStream } from '../common/streaming.js';\nimport {\n adaptBackendEvent,\n normalizeSimilarProductsResponse,\n normalizeProductGroupingsResponse,\n} from '../common/protocol-adapter.js';\nimport type { NormalizedProduct } from '../common/protocol-adapter.js';\nimport type { StreamEvent, UIElement } from '../common/types.js';\nimport type { ChatTransportConfig } from '../common/api-paths.js';\n\nexport interface SimilarProductsRequest {\n account_id: string;\n session_id: string;\n correlation_id: string;\n sku: string;\n domain?: string;\n limit?: number;\n output_language?: string;\n}\n\nexport interface ProductGroupingsRequest {\n account_id: string;\n session_id: string;\n correlation_id: string;\n skus: string[];\n output_language?: string;\n}\n\nexport interface ProductGroup {\n name: string;\n highlight?: string;\n products: NormalizedProduct[];\n}\n\nfunction extractProductCardsFromSpec(elements: Record<string, UIElement>): NormalizedProduct[] {\n const products: NormalizedProduct[] = [];\n for (const el of Object.values(elements)) {\n if (el.type === 'ProductCard' && el.props) {\n const product = (el.props['product'] ?? el.props) as Record<string, unknown>;\n if (typeof product['sku'] === 'string' && typeof product['name'] === 'string') {\n products.push(product as unknown as NormalizedProduct);\n }\n }\n }\n return products;\n}\n\nfunction isNDJSONResponse(response: Response): boolean {\n const ct = response.headers.get('Content-Type') ?? '';\n return ct.includes('application/x-ndjson') || ct.includes('text/event-stream');\n}\n\nasync function collectProductsFromStream(response: Response, signal?: AbortSignal): Promise<NormalizedProduct[]> {\n const products: NormalizedProduct[] = [];\n const opts: import('../common/streaming.js').StreamOptions = {\n onEvent: (event: StreamEvent) => {\n const normalized = adaptBackendEvent(event as unknown as Record<string, unknown>);\n if (!normalized || normalized.type !== 'ui_spec') return;\n\n products.push(...extractProductCardsFromSpec(normalized.spec.elements));\n },\n };\n if (signal !== undefined) opts.signal = signal;\n await consumeStream(response, opts);\n return products;\n}\n\nexport async function fetchSimilarProducts(\n request: SimilarProductsRequest,\n transport: ChatTransportConfig,\n signal?: AbortSignal,\n): Promise<NormalizedProduct[]> {\n const url = buildChatEndpointUrl('similar_products', transport);\n\n const fetchInit: RequestInit = {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(request),\n };\n if (signal !== undefined) fetchInit.signal = signal;\n const response = await fetch(url, fetchInit);\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n if (isNDJSONResponse(response)) {\n return collectProductsFromStream(response, signal);\n }\n\n const text = await response.text();\n if (!text) return [];\n try {\n return normalizeSimilarProductsResponse(JSON.parse(text));\n } catch {\n throw new Error(`Invalid JSON from similar_products endpoint`);\n }\n}\n\nasync function collectGroupingsFromStream(response: Response, signal?: AbortSignal): Promise<ProductGroup[]> {\n const groups: ProductGroup[] = [];\n let currentGroup: ProductGroup | null = null;\n\n const opts: import('../common/streaming.js').StreamOptions = {\n onEvent: (event: StreamEvent) => {\n const normalized = adaptBackendEvent(event as unknown as Record<string, unknown>);\n if (!normalized) return;\n\n if (normalized.type === 'metadata' && normalized.meta) {\n const name = normalized.meta['group_name'];\n if (typeof name === 'string') {\n currentGroup = { name, products: [] };\n const highlight = normalized.meta['highlight'];\n if (typeof highlight === 'string') currentGroup.highlight = highlight;\n groups.push(currentGroup);\n }\n }\n\n if (normalized.type === 'ui_spec' && currentGroup) {\n currentGroup.products.push(...extractProductCardsFromSpec(normalized.spec.elements));\n }\n },\n };\n if (signal !== undefined) opts.signal = signal;\n await consumeStream(response, opts);\n\n return groups;\n}\n\nexport async function fetchProductGroupings(\n request: ProductGroupingsRequest,\n transport: ChatTransportConfig,\n signal?: AbortSignal,\n): Promise<ProductGroup[]> {\n const url = buildChatEndpointUrl('product_groupings', transport);\n\n const fetchInit: RequestInit = {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(request),\n };\n if (signal !== undefined) fetchInit.signal = signal;\n const response = await fetch(url, fetchInit);\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n if (isNDJSONResponse(response)) {\n return collectGroupingsFromStream(response, signal);\n }\n\n const text = await response.text();\n if (!text) return [];\n try {\n return normalizeProductGroupingsResponse(JSON.parse(text));\n } catch {\n throw new Error(`Invalid JSON from product_groupings endpoint`);\n }\n}\n","import type { NormalizedProduct } from '../../common/protocol-adapter.js';\nimport type { SimRelI18n } from '../types.js';\nimport type { PriceFormatConfig } from '../../common/price-formatter.js';\nimport { formatPrice } from '../../common/price-formatter.js';\nimport { sanitizeHtml, isSafeImageUrl } from '../../common/safe-html.js';\nimport { createQuantityStepper } from '../../common/quantity-stepper.js';\nimport { clampDiscount, addImageErrorHandler, createStarRatingElement } from '../../common/product-utils.js';\n\nexport interface ProductCardOptions {\n product: NormalizedProduct;\n index: number;\n discountType?: 'strike-through' | 'badge';\n onClick: (product: NormalizedProduct) => void;\n onAddToCart: (params: { sku: string; quantity: number; cartCode: string }) => void;\n renderCard?: (product: NormalizedProduct, index: number) => string;\n i18n?: SimRelI18n;\n pricing?: PriceFormatConfig;\n}\n\nexport function renderProductCard(options: ProductCardOptions): HTMLElement {\n const { product, index, discountType, onClick, onAddToCart, renderCard } = options;\n const i18n = options.i18n;\n const pricing = options.pricing;\n\n // Custom card renderer (XSS warning: raw HTML injection)\n if (renderCard) {\n const wrapper = document.createElement('div');\n wrapper.className = 'gengage-simrel-card gengage-simrel-card--custom';\n // Sanitize renderCard output to prevent XSS from user-provided renderers.\n wrapper.innerHTML = sanitizeHtml(renderCard(product, index));\n wrapper.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.gengage-simrel-atc')) return;\n if ((e.target as HTMLElement).closest('.gengage-chat-product-card-atc')) return;\n onClick(product);\n });\n return wrapper;\n }\n\n const card = document.createElement('article');\n // Intentional class coupling: reuse chat product-card classes so SimRel and chat stay visually identical.\n card.className = 'gengage-simrel-card gengage-chat-product-card';\n card.setAttribute('role', 'listitem');\n card.dataset['sku'] = product.sku;\n\n // Image\n const imgWrapper = document.createElement('div');\n imgWrapper.className = 'gengage-simrel-card-image gengage-chat-product-card-img-wrapper';\n if (product.imageUrl && isSafeImageUrl(product.imageUrl)) {\n const img = document.createElement('img');\n img.className = 'gengage-chat-product-card-img';\n img.src = product.imageUrl;\n img.alt = product.name;\n img.loading = 'lazy';\n addImageErrorHandler(img);\n imgWrapper.appendChild(img);\n }\n\n // Discount badge\n if (discountType === 'badge' && product.discountPercent && product.discountPercent > 0) {\n const badge = document.createElement('span');\n badge.className = 'gengage-simrel-badge gengage-chat-product-card-discount-badge';\n badge.textContent = `%${clampDiscount(product.discountPercent)}`;\n imgWrapper.appendChild(badge);\n }\n\n card.appendChild(imgWrapper);\n\n // Info section\n const info = document.createElement('div');\n info.className = 'gengage-simrel-card-info gengage-chat-product-card-body';\n\n // Brand\n if (product.brand) {\n const brandEl = document.createElement('div');\n brandEl.className = 'gengage-simrel-card-brand gengage-chat-product-card-brand';\n brandEl.textContent = product.brand;\n info.appendChild(brandEl);\n }\n\n // Name\n const nameEl = document.createElement('div');\n nameEl.className = 'gengage-simrel-card-name gengage-chat-product-card-name';\n nameEl.textContent = product.name;\n info.appendChild(nameEl);\n\n // Rating\n if (product.rating != null && product.rating > 0) {\n const ratingEl = document.createElement('div');\n ratingEl.className = 'gengage-simrel-card-rating gengage-chat-product-card-rating';\n ratingEl.appendChild(createStarRatingElement(product.rating));\n if (product.reviewCount != null) {\n const count = document.createElement('span');\n count.className = 'gengage-simrel-card-review-count gengage-chat-product-card-review-count';\n count.textContent = ` (${product.reviewCount})`;\n ratingEl.appendChild(count);\n }\n info.appendChild(ratingEl);\n }\n\n // Price\n const priceContainer = document.createElement('div');\n priceContainer.className = 'gengage-simrel-card-price gengage-chat-product-card-price';\n\n if (product.originalPrice && product.originalPrice !== product.price) {\n if (discountType === 'strike-through' || !discountType) {\n const original = document.createElement('span');\n original.className = 'gengage-simrel-card-price-original gengage-chat-product-card-original-price';\n original.textContent = formatPrice(product.originalPrice, pricing);\n priceContainer.appendChild(original);\n }\n }\n\n if (product.price) {\n const current = document.createElement('span');\n current.className = 'gengage-simrel-card-price-current gengage-chat-product-card-price-current';\n current.textContent = formatPrice(product.price, pricing);\n priceContainer.appendChild(current);\n }\n\n info.appendChild(priceContainer);\n card.appendChild(info);\n\n // Keep SimRel cards aligned with chat product-card structure.\n const cta = document.createElement('button');\n cta.className = 'gengage-simrel-card-cta gengage-chat-product-card-cta';\n cta.type = 'button';\n cta.textContent = i18n?.ctaLabel ?? 'View';\n cta.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n onClick(product);\n });\n card.appendChild(cta);\n\n // Add to cart stepper or out-of-stock indicator\n if (product.inStock === false) {\n const oos = document.createElement('div');\n oos.className = 'gengage-simrel-card-oos';\n oos.textContent = i18n?.outOfStockLabel ?? 'Out of Stock';\n card.appendChild(oos);\n } else if (product.cartCode) {\n const cartCode = product.cartCode;\n const stepper = createQuantityStepper({\n compact: true,\n label: i18n?.addToCartButton ?? 'Add to Cart',\n onSubmit: (quantity) => {\n onAddToCart({ sku: product.sku, quantity, cartCode });\n },\n });\n stepper.classList.add('gengage-simrel-atc');\n card.appendChild(stepper);\n }\n\n // Card click → navigate\n card.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.gengage-simrel-atc')) return;\n if ((e.target as HTMLElement).closest('.gengage-chat-product-card-atc')) return;\n if ((e.target as HTMLElement).closest('.gengage-chat-product-card-cta')) return;\n onClick(product);\n });\n\n return card;\n}\n","import type { NormalizedProduct } from '../../common/protocol-adapter.js';\nimport type { SimRelI18n } from '../types.js';\nimport { renderProductCard } from './ProductCard.js';\nimport type { ProductCardOptions } from './ProductCard.js';\n\nexport interface ProductGridOptions {\n products: NormalizedProduct[];\n columns?: number;\n discountType?: 'strike-through' | 'badge';\n onClick: (product: NormalizedProduct) => void;\n onAddToCart: (params: { sku: string; quantity: number; cartCode: string }) => void;\n renderCard?: (product: NormalizedProduct, index: number) => string;\n i18n?: SimRelI18n;\n}\n\nexport function renderProductGrid(options: ProductGridOptions): HTMLElement {\n const grid = document.createElement('div');\n grid.className = 'gengage-simrel-grid';\n grid.setAttribute('role', 'list');\n grid.setAttribute('aria-label', options.i18n?.similarProductsAriaLabel ?? 'Similar products');\n\n if (options.columns) {\n grid.style.setProperty('--gengage-simrel-columns', String(options.columns));\n }\n\n for (let i = 0; i < options.products.length; i++) {\n const product = options.products[i]!;\n const cardOpts: ProductCardOptions = {\n product,\n index: i,\n onClick: options.onClick,\n onAddToCart: options.onAddToCart,\n };\n if (options.i18n !== undefined) cardOpts.i18n = options.i18n;\n if (options.discountType !== undefined) cardOpts.discountType = options.discountType;\n if (options.renderCard !== undefined) cardOpts.renderCard = options.renderCard;\n const card = renderProductCard(cardOpts);\n grid.appendChild(card);\n }\n\n if (options.products.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'gengage-simrel-empty';\n empty.textContent = options.i18n?.emptyStateMessage ?? 'No similar products found.';\n grid.appendChild(empty);\n }\n\n return grid;\n}\n","import type { NormalizedProduct } from '../../common/protocol-adapter.js';\nimport type { ProductGroup } from '../api.js';\nimport type { SimRelI18n } from '../types.js';\nimport { renderProductGrid } from './ProductGrid.js';\n\nexport interface GroupTabsOptions {\n groups: ProductGroup[];\n discountType?: 'strike-through' | 'badge';\n onClick: (product: NormalizedProduct) => void;\n onAddToCart: (params: { sku: string; quantity: number; cartCode: string }) => void;\n renderCard?: (product: NormalizedProduct, index: number) => string;\n i18n?: SimRelI18n;\n}\n\nlet _groupTabsInstanceCounter = 0;\n\nexport function renderGroupTabs(options: GroupTabsOptions): HTMLElement {\n const instanceId = _groupTabsInstanceCounter++;\n const container = document.createElement('div');\n container.className = 'gengage-simrel-groups';\n\n if (options.groups.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'gengage-simrel-empty';\n empty.textContent = options.i18n?.emptyStateMessage ?? 'No similar products found.';\n container.appendChild(empty);\n return container;\n }\n\n // Tab bar — WAI-ARIA tablist pattern\n const tabBar = document.createElement('div');\n tabBar.className = 'gengage-simrel-tabs';\n tabBar.setAttribute('role', 'tablist');\n\n const tabs: HTMLButtonElement[] = [];\n const panels: HTMLElement[] = [];\n\n const buildGridOptions = (group: ProductGroup): import('./ProductGrid.js').ProductGridOptions => {\n const gridOpts: import('./ProductGrid.js').ProductGridOptions = {\n products: group.products,\n onClick: options.onClick,\n onAddToCart: options.onAddToCart,\n };\n if (options.i18n !== undefined) gridOpts.i18n = options.i18n;\n if (options.discountType !== undefined) gridOpts.discountType = options.discountType;\n if (options.renderCard !== undefined) gridOpts.renderCard = options.renderCard;\n return gridOpts;\n };\n\n const activateTab = (index: number): void => {\n for (let j = 0; j < tabs.length; j++) {\n const isActive = j === index;\n tabs[j]!.classList.toggle('gengage-simrel-tab--active', isActive);\n tabs[j]!.setAttribute('aria-selected', String(isActive));\n tabs[j]!.tabIndex = isActive ? 0 : -1;\n }\n\n // Lazy-render the grid content for the active panel\n const group = options.groups[index]!;\n const panel = panels[index]!;\n panel.innerHTML = '';\n const grid = renderProductGrid(buildGridOptions(group));\n panel.appendChild(grid);\n\n // Show only the active panel and manage tabindex for keyboard access\n for (let j = 0; j < panels.length; j++) {\n const isActive = j === index;\n panels[j]!.style.display = isActive ? '' : 'none';\n panels[j]!.tabIndex = isActive ? 0 : -1;\n }\n };\n\n for (let i = 0; i < options.groups.length; i++) {\n const group = options.groups[i]!;\n const tabId = `gengage-simrel-tab-${instanceId}-${i}`;\n const panelId = `gengage-simrel-panel-${instanceId}-${i}`;\n\n // Tab button\n const tab = document.createElement('button');\n tab.className = 'gengage-simrel-tab';\n tab.type = 'button';\n tab.id = tabId;\n tab.textContent = group.name;\n tab.setAttribute('role', 'tab');\n tab.setAttribute('aria-controls', panelId);\n tab.setAttribute('aria-selected', String(i === 0));\n tab.tabIndex = i === 0 ? 0 : -1;\n if (i === 0) tab.classList.add('gengage-simrel-tab--active');\n\n tab.addEventListener('click', () => activateTab(i));\n tab.addEventListener('keydown', (e: KeyboardEvent) => {\n let next = -1;\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n next = (i + 1) % options.groups.length;\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n next = (i - 1 + options.groups.length) % options.groups.length;\n } else if (e.key === 'Home') {\n next = 0;\n } else if (e.key === 'End') {\n next = options.groups.length - 1;\n }\n if (next >= 0) {\n e.preventDefault();\n activateTab(next);\n tabs[next]!.focus();\n }\n });\n\n tabs.push(tab);\n tabBar.appendChild(tab);\n\n // Tab panel\n const panel = document.createElement('div');\n panel.className = 'gengage-simrel-tab-panel';\n panel.id = panelId;\n panel.setAttribute('role', 'tabpanel');\n panel.setAttribute('aria-labelledby', tabId);\n panel.tabIndex = i === 0 ? 0 : -1;\n if (i !== 0) panel.style.display = 'none';\n\n panels.push(panel);\n }\n\n container.appendChild(tabBar);\n\n // Render the initial (first) tab content\n const firstPanel = panels[0]!;\n const firstGrid = renderProductGrid(buildGridOptions(options.groups[0]!));\n firstPanel.appendChild(firstGrid);\n\n for (const panel of panels) container.appendChild(panel);\n\n return container;\n}\n","import { renderUISpecWithRegistry } from '../../common/renderer/index.js';\nimport type { UISpecDomRegistry, UISpecDomUnknownRenderer } from '../../common/renderer/index.js';\nimport type { UISpec, ActionPayload } from '../../common/types.js';\nimport type { SimRelUISpecRenderContext, SimilarProduct } from '../types.js';\nimport type { ProductGroup } from '../api.js';\nimport { renderProductCard } from './ProductCard.js';\nimport { renderGroupTabs } from './GroupTabs.js';\n\nexport type SimRelUISpecRegistry = UISpecDomRegistry<SimRelUISpecRenderContext>;\n\nfunction toSimRelProduct(raw: unknown): SimilarProduct | null {\n if (!raw || typeof raw !== 'object') return null;\n const obj = raw as Record<string, unknown>;\n if (typeof obj['sku'] !== 'string' || typeof obj['name'] !== 'string' || typeof obj['url'] !== 'string') {\n return null;\n }\n\n const result: SimilarProduct = {\n sku: obj['sku'],\n name: obj['name'],\n url: obj['url'],\n };\n\n const imageUrl = obj['imageUrl'];\n if (typeof imageUrl === 'string') result.imageUrl = imageUrl;\n const price = obj['price'];\n if (typeof price === 'string') result.price = price;\n const originalPrice = obj['originalPrice'];\n if (typeof originalPrice === 'string') result.originalPrice = originalPrice;\n const discountPercent = obj['discountPercent'];\n if (typeof discountPercent === 'number') result.discountPercent = discountPercent;\n const brand = obj['brand'];\n if (typeof brand === 'string') result.brand = brand;\n const rating = obj['rating'];\n if (typeof rating === 'number') result.rating = rating;\n const reviewCount = obj['reviewCount'];\n if (typeof reviewCount === 'number') result.reviewCount = reviewCount;\n const cartCode = obj['cartCode'];\n if (typeof cartCode === 'string') result.cartCode = cartCode;\n const inStock = obj['inStock'];\n if (typeof inStock === 'boolean') result.inStock = inStock;\n\n return result;\n}\n\nfunction toActionPayload(raw: unknown): ActionPayload | null {\n if (!raw || typeof raw !== 'object') return null;\n const obj = raw as Record<string, unknown>;\n const title = obj['title'];\n const type = obj['type'];\n if (typeof title !== 'string' || typeof type !== 'string') return null;\n const action: ActionPayload = { title, type };\n if (obj['payload'] !== undefined) action.payload = obj['payload'];\n return action;\n}\n\nconst DEFAULT_SIMREL_UI_SPEC_REGISTRY: SimRelUISpecRegistry = {\n ProductGrid: ({ element, renderElement, context }) => {\n const grid = document.createElement('div');\n grid.className = 'gengage-simrel-grid';\n grid.setAttribute('role', 'list');\n\n const columns = element.props?.['columns'];\n if (typeof columns === 'number' && Number.isFinite(columns) && columns > 0) {\n grid.style.setProperty('--gengage-simrel-columns', String(columns));\n }\n\n for (const childId of element.children ?? []) {\n const rendered = renderElement(childId);\n if (rendered) grid.appendChild(rendered);\n }\n\n if (grid.children.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'gengage-simrel-empty';\n empty.textContent = context.i18n.emptyStateMessage;\n grid.appendChild(empty);\n }\n\n return grid;\n },\n\n ProductCard: ({ element, context }) => {\n const productRaw = (element.props?.['product'] ?? element.props) as unknown;\n const product = toSimRelProduct(productRaw);\n if (!product) return null;\n\n const indexRaw = element.props?.['index'];\n const index = typeof indexRaw === 'number' && Number.isFinite(indexRaw) ? indexRaw : 0;\n const discountTypeRaw = element.props?.['discountType'];\n const discountType =\n discountTypeRaw === 'strike-through' || discountTypeRaw === 'badge' ? discountTypeRaw : context.discountType;\n\n const options: import('./ProductCard.js').ProductCardOptions = {\n product,\n index,\n onClick: context.onClick,\n onAddToCart: context.onAddToCart,\n i18n: context.i18n,\n };\n if (discountType !== undefined) options.discountType = discountType;\n if (context.renderCard !== undefined) options.renderCard = context.renderCard;\n if (context.pricing !== undefined) options.pricing = context.pricing;\n return renderProductCard(options);\n },\n\n GroupTabs: ({ element, context }) => {\n const groupsRaw = element.props?.['groups'];\n if (!Array.isArray(groupsRaw)) return null;\n const groups: ProductGroup[] = [];\n\n for (const entry of groupsRaw) {\n if (!entry || typeof entry !== 'object') continue;\n const obj = entry as Record<string, unknown>;\n if (typeof obj['name'] !== 'string') continue;\n\n const products: SimilarProduct[] = [];\n if (Array.isArray(obj['products'])) {\n for (const rawProduct of obj['products']) {\n const normalized = toSimRelProduct(rawProduct);\n if (normalized) products.push(normalized);\n }\n }\n\n const group: ProductGroup = {\n name: obj['name'],\n products,\n };\n if (typeof obj['highlight'] === 'string') group.highlight = obj['highlight'];\n groups.push(group);\n }\n\n const options: import('./GroupTabs.js').GroupTabsOptions = {\n groups,\n onClick: context.onClick,\n onAddToCart: context.onAddToCart,\n i18n: context.i18n,\n };\n if (context.discountType !== undefined) options.discountType = context.discountType;\n if (context.renderCard !== undefined) options.renderCard = context.renderCard;\n return renderGroupTabs(options);\n },\n\n EmptyState: ({ element, context }) => {\n const empty = document.createElement('div');\n empty.className = 'gengage-simrel-empty';\n const message = element.props?.['message'];\n empty.textContent = typeof message === 'string' ? message : context.i18n.emptyStateMessage;\n return empty;\n },\n\n AddToCartButton: ({ element, context }) => {\n const sku = element.props?.['sku'];\n const cartCode = element.props?.['cartCode'];\n if (typeof sku !== 'string' || typeof cartCode !== 'string') return null;\n\n const button = document.createElement('button');\n button.className = 'gengage-simrel-atc gengage-chat-product-card-cta';\n button.type = 'button';\n const label = element.props?.['label'];\n button.textContent = typeof label === 'string' ? label : context.i18n.addToCartButton;\n button.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n context.onAddToCart({ sku, quantity: 1, cartCode });\n });\n return button;\n },\n\n QuickActions: ({ element, context }) => {\n const wrapper = document.createElement('div');\n wrapper.className = 'gengage-simrel-quick-actions';\n const actions = element.props?.['actions'];\n if (!Array.isArray(actions) || !context.onAction) return wrapper;\n\n for (const raw of actions) {\n if (!raw || typeof raw !== 'object') continue;\n const actionObj = raw as Record<string, unknown>;\n const label = actionObj['label'];\n const action = toActionPayload(actionObj['action']);\n if (typeof label !== 'string' || !action) continue;\n\n const button = document.createElement('button');\n button.className = 'gengage-simrel-quick-action';\n button.type = 'button';\n button.textContent = label;\n button.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n context.onAction?.(action);\n });\n wrapper.appendChild(button);\n }\n return wrapper;\n },\n};\n\nexport const defaultSimRelUnknownUISpecRenderer: UISpecDomUnknownRenderer<SimRelUISpecRenderContext> = ({\n element,\n renderElement,\n}) => {\n if (import.meta.env?.DEV) {\n console.warn(`[gengage:simrel] Unknown ui_spec component type: ${element.type}`);\n }\n if (!element.children || element.children.length === 0) {\n return null;\n }\n const wrapper = document.createElement('div');\n for (const childId of element.children) {\n const rendered = renderElement(childId);\n if (rendered) wrapper.appendChild(rendered);\n }\n return wrapper;\n};\n\nexport function createDefaultSimRelUISpecRegistry(): SimRelUISpecRegistry {\n return { ...DEFAULT_SIMREL_UI_SPEC_REGISTRY };\n}\n\nexport function renderSimRelUISpec(\n spec: UISpec,\n context: SimRelUISpecRenderContext,\n registry = DEFAULT_SIMREL_UI_SPEC_REGISTRY,\n unknownRenderer: UISpecDomUnknownRenderer<SimRelUISpecRenderContext> = defaultSimRelUnknownUISpecRenderer,\n): HTMLElement {\n return renderUISpecWithRegistry({\n spec,\n context,\n registry,\n containerClassName: 'gengage-simrel-uispec',\n unknownRenderer,\n });\n}\n","import type { SimRelI18n } from '../types.js';\n\nexport const SIMREL_I18N_TR: SimRelI18n = {\n similarProductsAriaLabel: 'Benzer ürünler',\n emptyStateMessage: 'Benzer ürün bulunamadı.',\n addToCartButton: 'Sepete Ekle',\n ctaLabel: 'İncele',\n outOfStockLabel: 'Stokta Yok',\n priceSuffix: ' TL',\n};\n","import type { SimRelI18n } from '../types.js';\n\nexport const SIMREL_I18N_EN: SimRelI18n = {\n similarProductsAriaLabel: 'Similar products',\n emptyStateMessage: 'No similar products found.',\n addToCartButton: 'Add to cart',\n ctaLabel: 'View',\n outOfStockLabel: 'Out of Stock',\n priceSuffix: '',\n};\n","import type { SimRelI18n } from '../types.js';\nimport { SIMREL_I18N_TR } from './tr.js';\nimport { SIMREL_I18N_EN } from './en.js';\n\nfunction normalizeLocale(locale?: string): string {\n if (!locale) return 'tr';\n return locale.toLowerCase().split('-')[0] ?? 'tr';\n}\n\nexport function resolveSimRelLocale(locale?: string): SimRelI18n {\n switch (normalizeLocale(locale)) {\n case 'en':\n return SIMREL_I18N_EN;\n default:\n return SIMREL_I18N_TR;\n }\n}\n\nexport { SIMREL_I18N_TR, SIMREL_I18N_EN };\n","/**\n * Similar Products (SimRel) widget — json-render catalog definition.\n *\n * Backend endpoints:\n * POST /chat/similar_products — primary product list\n * POST /chat/product_groupings — grouped/tabbed view\n *\n * The backend streams NDJSON events. `ui_spec` events reference\n * component names defined below. Implementations live in ./registry.\n */\n\nimport { z } from 'zod';\n\nconst SimilarProductSchema = z.object({\n sku: z.string(),\n name: z.string(),\n imageUrl: z.string().url().optional(),\n price: z.string().optional(),\n originalPrice: z.string().optional(),\n discountPercent: z.number().optional(),\n url: z.string().url(),\n brand: z.string().optional(),\n rating: z.number().min(0).max(5).optional(),\n reviewCount: z.number().int().nonnegative().optional(),\n});\n\nexport const ProductGridSchema = z.object({\n layout: z.enum(['grid', 'carousel']).optional(),\n columns: z.number().int().positive().optional(),\n});\n\nexport const ProductCardSchema = z.object({\n product: SimilarProductSchema,\n index: z.number().int().nonnegative(),\n discountType: z.enum(['strike-through', 'badge']).optional(),\n});\n\nexport const AddToCartButtonSchema = z.object({\n sku: z.string(),\n label: z.string().optional(),\n cartCode: z.string(),\n});\n\nexport const QuickActionsSchema = z.object({\n actions: z.array(\n z.object({\n label: z.string(),\n action: z.object({\n title: z.string(),\n type: z.string(),\n payload: z.unknown().optional(),\n }),\n }),\n ),\n});\n\nexport const EmptyStateSchema = z.object({\n message: z.string().optional(),\n});\n\nexport const simRelCatalog = {\n components: {\n ProductGrid: {\n schema: ProductGridSchema,\n description: 'Outer grid or carousel container for similar products.',\n },\n ProductCard: {\n schema: ProductCardSchema,\n description: 'A single product card with image, title, price, and actions.',\n },\n AddToCartButton: {\n schema: AddToCartButtonSchema,\n description: 'Add-to-cart CTA rendered inside or below a product card.',\n },\n QuickActions: {\n schema: QuickActionsSchema,\n description: 'A row of quick-action buttons below product info.',\n },\n EmptyState: {\n schema: EmptyStateSchema,\n description: 'Empty state shown when no similar products are available.',\n },\n },\n} as const;\n\nexport type SimRelCatalog = typeof simRelCatalog;\nexport type SimRelComponentName = keyof SimRelCatalog['components'];\n","/**\n * Similar Products (SimRel) widget — public entry point.\n *\n * Fetches and renders similar / related products for the current SKU.\n * Backend: POST /chat/similar_products + /chat/product_groupings\n */\n\nimport type { PageContext, UISpec, UIElement } from '../common/types.js';\nimport type { NormalizedProduct } from '../common/protocol-adapter.js';\nimport type { ChatTransportConfig } from '../common/api-paths.js';\nimport type { UISpecRenderHelpers } from '../common/renderer/index.js';\nimport { mergeUISpecRegistry } from '../common/renderer/index.js';\nimport { BaseWidget } from '../common/widget-base.js';\nimport { dispatch } from '../common/events.js';\nimport { getGlobalErrorMessage } from '../common/global-error-toast.js';\nimport {\n streamStartEvent,\n streamDoneEvent,\n streamErrorEvent,\n basketAddEvent,\n widgetHistorySnapshotEvent,\n} from '../common/analytics-events.js';\nimport { fetchSimilarProducts, fetchProductGroupings } from './api.js';\nimport {\n createDefaultSimRelUISpecRegistry,\n defaultSimRelUnknownUISpecRenderer,\n renderSimRelUISpec,\n} from './components/renderUISpec.js';\nimport type { SimRelWidgetConfig, SimilarProduct, SimRelI18n, SimRelUISpecRenderContext } from './types.js';\nimport { SIMREL_I18N_TR, resolveSimRelLocale } from './locales/index.js';\nimport * as ga from '../common/ga-datalayer.js';\n\nimport './components/simrel.css';\n\n/**\n * Similar / related products widget for product pages.\n * Fetches AI-powered product recommendations and renders them as a scrollable grid.\n *\n * @example\n * ```ts\n * import { GengageSimRel, bootstrapSession } from '@gengage/assistant-fe';\n *\n * const simrel = new GengageSimRel();\n * await simrel.init({\n * accountId: 'mystore',\n * middlewareUrl: 'https://chat.gengage.ai',\n * sku: '12345',\n * mountTarget: '#similar-products',\n * session: { sessionId: bootstrapSession() },\n * onAddToCart: ({ sku, quantity }) => cart.add(sku, quantity),\n * });\n * ```\n */\nexport class GengageSimRel extends BaseWidget<SimRelWidgetConfig> {\n private _abortController: AbortController | null = null;\n private _contentEl: HTMLElement | null = null;\n private _lastSku: string | undefined;\n private _i18n: SimRelI18n = SIMREL_I18N_TR;\n\n protected async onInit(config: SimRelWidgetConfig): Promise<void> {\n this._i18n = this._resolveI18n(config);\n\n this._contentEl = document.createElement('div');\n this._contentEl.className = 'gengage-simrel-container';\n this.root.appendChild(this._contentEl);\n\n this._lastSku = config.sku;\n await this._fetchAndRender(config.sku);\n this.isVisible = true;\n ga.trackInit('simrel');\n }\n\n protected onUpdate(context: Partial<PageContext>): void {\n const newSku = context.sku;\n if (!newSku || newSku === this._lastSku) return;\n this._lastSku = newSku;\n void this._fetchAndRender(newSku);\n }\n\n protected onShow(): void {\n if (this._contentEl) {\n this._contentEl.style.opacity = '0';\n this._contentEl.style.transition = 'opacity 0.3s ease-in';\n requestAnimationFrame(() => {\n if (this._contentEl) this._contentEl.style.opacity = '1';\n });\n }\n }\n\n protected onHide(): void {\n // Preserve fetched products for re-show\n }\n\n protected onDestroy(): void {\n this._abort();\n if (this._contentEl) {\n this._contentEl.remove();\n this._contentEl = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal event dispatchers\n // ---------------------------------------------------------------------------\n\n _handleProductClick(product: NormalizedProduct): void {\n const simRelProduct: SimilarProduct = {\n sku: product.sku,\n name: product.name,\n url: product.url,\n };\n if (product.imageUrl !== undefined) simRelProduct.imageUrl = product.imageUrl;\n if (product.price !== undefined) simRelProduct.price = product.price;\n if (product.originalPrice !== undefined) simRelProduct.originalPrice = product.originalPrice;\n if (product.discountPercent !== undefined) simRelProduct.discountPercent = product.discountPercent;\n if (product.brand !== undefined) simRelProduct.brand = product.brand;\n if (product.rating !== undefined) simRelProduct.rating = product.rating;\n if (product.reviewCount !== undefined) simRelProduct.reviewCount = product.reviewCount;\n if (product.cartCode !== undefined) simRelProduct.cartCode = product.cartCode;\n if (product.inStock !== undefined) simRelProduct.inStock = product.inStock;\n\n if (this.config.onProductClick?.(simRelProduct) === false) return;\n\n ga.trackProductDetail(product.sku, product.name);\n const sessionId = this.config.session?.sessionId ?? null;\n dispatch('gengage:similar:product-click', {\n sku: product.sku,\n url: product.url,\n sessionId,\n });\n\n this.config.onProductNavigate?.(product.url, product.sku, sessionId);\n }\n\n _handleAddToCart(params: { sku: string; quantity: number; cartCode: string }): void {\n ga.trackCartAdd(params.sku, params.quantity);\n this.config.onAddToCart?.(params);\n dispatch('gengage:similar:add-to-cart', params);\n\n this.track(\n basketAddEvent(this.analyticsContext(), {\n attribution_source: 'simrel',\n attribution_action_id: crypto.randomUUID(),\n cart_value: 0, // Host page should enrich via event listener\n currency: 'TRY',\n line_items: params.quantity,\n sku: params.sku,\n }),\n );\n }\n\n // ---------------------------------------------------------------------------\n // Private\n // ---------------------------------------------------------------------------\n\n private _abort(): void {\n this._abortController?.abort();\n this._abortController = null;\n }\n\n private async _fetchAndRender(sku: string): Promise<void> {\n this._abort();\n this._abortController = new AbortController();\n // Capture signal reference at invocation time to avoid race conditions:\n // if onUpdate fires between awaits, `this._abortController` gets swapped\n // but `signal` still refers to this invocation's controller.\n const signal = this._abortController.signal;\n\n if (!this._contentEl) return;\n this._contentEl.innerHTML = '';\n // Reset visibility in case a previous error set display:none\n this._contentEl.style.display = '';\n\n // Show loading spinner\n const loading = document.createElement('div');\n loading.className = 'gengage-simrel-loading';\n const spinner = document.createElement('div');\n spinner.className = 'gengage-simrel-spinner';\n loading.appendChild(spinner);\n this._contentEl.appendChild(loading);\n\n const transport: ChatTransportConfig = {\n middlewareUrl: this.config.middlewareUrl,\n };\n\n const requestId = crypto.randomUUID();\n const fetchStart = Date.now();\n\n this.track(\n streamStartEvent(this.analyticsContext(), {\n endpoint: 'similar_products',\n request_id: requestId,\n widget: 'simrel',\n }),\n );\n\n try {\n // Fetch similar products\n const simReq: import('./api.js').SimilarProductsRequest = {\n account_id: this.config.accountId,\n session_id: this.config.session?.sessionId ?? '',\n correlation_id: this.config.session?.sessionId ?? '',\n sku,\n };\n if (this.config.domain !== undefined) simReq.domain = this.config.domain;\n const products = await fetchSimilarProducts(simReq, transport, signal);\n\n if (!this._contentEl) return;\n this._contentEl.innerHTML = '';\n\n // Try to fetch product groupings for tabbed view\n if (products.length > 0) {\n try {\n const skus = products.map((p) => p.sku);\n const groups = await fetchProductGroupings(\n {\n account_id: this.config.accountId,\n session_id: this.config.session?.sessionId ?? '',\n correlation_id: this.config.session?.sessionId ?? '',\n skus,\n },\n transport,\n signal,\n );\n\n if (groups.length > 0 && this._contentEl) {\n const groupsSpec = this._buildGroupsSpec(groups);\n const renderedGroups = this._renderUISpec(groupsSpec);\n this._contentEl.appendChild(renderedGroups);\n\n ga.trackShow('simrel');\n this.track(\n streamDoneEvent(this.analyticsContext(), {\n request_id: requestId,\n latency_ms: Date.now() - fetchStart,\n chunk_count: groups.reduce((n, g) => n + g.products.length, 0),\n widget: 'simrel',\n }),\n );\n this.track(\n widgetHistorySnapshotEvent(this.analyticsContext(), {\n message_count: groups.reduce((n, g) => n + g.products.length, 0),\n history_ref: requestId,\n redaction_level: 'none',\n widget: 'simrel',\n }),\n );\n return;\n }\n } catch {\n // Product groupings is optional; fall through to flat grid\n }\n }\n\n // Flat grid (no groupings or groupings failed)\n if (this._contentEl) {\n const gridSpec = this._buildProductsSpec(products);\n const renderedGrid = this._renderUISpec(gridSpec);\n this._contentEl.appendChild(renderedGrid);\n }\n\n if (products.length > 0) {\n ga.trackShow('simrel');\n }\n\n this.track(\n streamDoneEvent(this.analyticsContext(), {\n request_id: requestId,\n latency_ms: Date.now() - fetchStart,\n chunk_count: products.length,\n widget: 'simrel',\n }),\n );\n\n this.track(\n widgetHistorySnapshotEvent(this.analyticsContext(), {\n message_count: products.length,\n history_ref: requestId,\n redaction_level: 'none',\n widget: 'simrel',\n }),\n );\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') return;\n\n dispatch('gengage:global:error', {\n source: 'simrel',\n code: 'FETCH_ERROR',\n message: getGlobalErrorMessage(this.config.locale),\n });\n\n this.track(\n streamErrorEvent(this.analyticsContext(), {\n request_id: requestId,\n error_code: 'FETCH_ERROR',\n error_message: err instanceof Error ? err.message : String(err),\n widget: 'simrel',\n }),\n );\n\n if (import.meta.env?.DEV) {\n console.error('[gengage:simrel] Failed to fetch similar products:', err);\n }\n // Show inline error with retry instead of hiding silently\n if (this._contentEl) {\n this._contentEl.innerHTML = '';\n const errorEl = document.createElement('div');\n errorEl.className = 'gengage-simrel-error';\n errorEl.style.cssText = 'text-align:center;padding:16px;color:#6b7280;font-size:13px;';\n const msgEl = document.createElement('span');\n msgEl.textContent = this.config.locale?.startsWith('tr')\n ? 'Benzer \\u00FCr\\u00FCnler y\\u00FCklenemedi.'\n : 'Could not load similar products.';\n errorEl.appendChild(msgEl);\n const retryBtn = document.createElement('button');\n retryBtn.textContent = this.config.locale?.startsWith('tr') ? 'Tekrar dene' : 'Try again';\n retryBtn.style.cssText =\n 'margin-left:8px;border:1px solid #d1d5db;background:#fff;border-radius:6px;padding:4px 12px;cursor:pointer;font-size:13px;color:#374151;';\n retryBtn.addEventListener('click', () => {\n void this._fetchAndRender(this.config.sku);\n });\n errorEl.appendChild(retryBtn);\n this._contentEl.appendChild(errorEl);\n }\n }\n }\n\n private _resolveI18n(config: SimRelWidgetConfig): SimRelI18n {\n const base = resolveSimRelLocale(config.locale);\n return { ...base, ...config.i18n };\n }\n\n private _resolveUISpecRegistry() {\n const baseRegistry = createDefaultSimRelUISpecRegistry();\n return mergeUISpecRegistry(baseRegistry, this.config.renderer?.registry);\n }\n\n private _buildRenderContext(): SimRelUISpecRenderContext {\n const renderCard = this.config.renderCard as ((product: SimilarProduct, index: number) => string) | undefined;\n const context: SimRelUISpecRenderContext = {\n onClick: (product) => this._handleProductClick(product as unknown as NormalizedProduct),\n onAddToCart: (params) => this._handleAddToCart(params),\n i18n: this._i18n,\n };\n if (this.config.discountType !== undefined) context.discountType = this.config.discountType;\n if (renderCard !== undefined) context.renderCard = renderCard;\n if (this.config.pricing !== undefined) context.pricing = this.config.pricing;\n return context;\n }\n\n private _renderUISpec(spec: UISpec): HTMLElement {\n const registry = this._resolveUISpecRegistry();\n const context = this._buildRenderContext();\n const unknownRenderer = this.config.renderer?.unknownRenderer ?? defaultSimRelUnknownUISpecRenderer;\n const defaultRender = (inputSpec: UISpec, inputContext: SimRelUISpecRenderContext) =>\n renderSimRelUISpec(inputSpec, inputContext, registry, unknownRenderer);\n\n const override = this.config.renderer?.renderUISpec;\n if (!override) return defaultRender(spec, context);\n\n const helpers: UISpecRenderHelpers<SimRelUISpecRenderContext> = {\n registry,\n unknownRenderer,\n defaultRender,\n };\n return override(spec, context, helpers);\n }\n\n private _buildProductsSpec(products: NormalizedProduct[]): UISpec {\n const elements: Record<string, UIElement> = {};\n const children: string[] = [];\n for (let i = 0; i < products.length; i++) {\n const product = products[i]!;\n const id = `product-${i}`;\n children.push(id);\n elements[id] = {\n type: 'ProductCard',\n props: {\n product,\n index: i,\n discountType: this.config.discountType,\n },\n };\n }\n elements['root'] = {\n type: 'ProductGrid',\n props: {\n layout: 'grid',\n },\n children,\n };\n return {\n root: 'root',\n elements,\n };\n }\n\n private _buildGroupsSpec(\n groups: Array<{\n name: string;\n highlight?: string;\n products: NormalizedProduct[];\n }>,\n ): UISpec {\n return {\n root: 'root',\n elements: {\n root: {\n type: 'GroupTabs',\n props: { groups },\n },\n },\n };\n }\n}\n\nexport function createSimRelWidget(): GengageSimRel {\n return new GengageSimRel();\n}\n\nexport type {\n SimRelWidgetConfig,\n SimilarProduct,\n SimRelUIComponents,\n SimRelI18n,\n SimRelUISpecRenderContext,\n SimRelRendererConfig,\n} from './types.js';\nexport {\n renderSimRelUISpec,\n createDefaultSimRelUISpecRegistry,\n defaultSimRelUnknownUISpecRenderer,\n} from './components/renderUISpec.js';\nexport type { SimRelUISpecRegistry } from './components/renderUISpec.js';\nexport { simRelCatalog } from './catalog.js';\nexport type { SimRelCatalog, SimRelComponentName } from './catalog.js';\n"],"names":["extractProductCardsFromSpec","elements","products","el","product","isNDJSONResponse","response","ct","collectProductsFromStream","signal","opts","event","normalized","adaptBackendEvent","consumeStream","fetchSimilarProducts","request","transport","url","buildChatEndpointUrl","fetchInit","text","normalizeSimilarProductsResponse","collectGroupingsFromStream","groups","currentGroup","name","highlight","fetchProductGroupings","normalizeProductGroupingsResponse","renderProductCard","options","index","discountType","onClick","onAddToCart","renderCard","i18n","pricing","wrapper","sanitizeHtml","e","card","imgWrapper","isSafeImageUrl","img","addImageErrorHandler","badge","clampDiscount","info","brandEl","nameEl","ratingEl","createStarRatingElement","count","priceContainer","original","formatPrice","current","cta","oos","cartCode","stepper","createQuantityStepper","quantity","renderProductGrid","grid","i","cardOpts","empty","_groupTabsInstanceCounter","renderGroupTabs","instanceId","container","tabBar","tabs","panels","buildGridOptions","group","gridOpts","activateTab","j","isActive","panel","tabId","panelId","tab","next","firstPanel","firstGrid","toSimRelProduct","raw","obj","result","imageUrl","price","originalPrice","discountPercent","brand","rating","reviewCount","inStock","toActionPayload","title","type","action","DEFAULT_SIMREL_UI_SPEC_REGISTRY","element","renderElement","context","columns","childId","rendered","productRaw","indexRaw","discountTypeRaw","groupsRaw","entry","rawProduct","message","sku","button","label","actions","actionObj","defaultSimRelUnknownUISpecRenderer","createDefaultSimRelUISpecRegistry","renderSimRelUISpec","spec","registry","unknownRenderer","renderUISpecWithRegistry","SIMREL_I18N_TR","SIMREL_I18N_EN","normalizeLocale","locale","resolveSimRelLocale","SimilarProductSchema","z.object","z.string","z.number","ProductGridSchema","z.enum","ProductCardSchema","AddToCartButtonSchema","QuickActionsSchema","z.array","z.unknown","EmptyStateSchema","simRelCatalog","GengageSimRel","BaseWidget","config","ga.trackInit","newSku","simRelProduct","ga.trackProductDetail","sessionId","dispatch","params","ga.trackCartAdd","basketAddEvent","loading","spinner","requestId","fetchStart","streamStartEvent","simReq","skus","p","groupsSpec","renderedGroups","ga.trackShow","streamDoneEvent","n","g","widgetHistorySnapshotEvent","gridSpec","renderedGrid","err","getGlobalErrorMessage","streamErrorEvent","errorEl","msgEl","retryBtn","baseRegistry","mergeUISpecRegistry","defaultRender","inputSpec","inputContext","override","children","id","createSimRelWidget"],"mappings":";;AAmCA,SAASA,EAA4BC,GAA0D;AAC7F,QAAMC,IAAgC,CAAA;AACtC,aAAWC,KAAM,OAAO,OAAOF,CAAQ;AACrC,QAAIE,EAAG,SAAS,iBAAiBA,EAAG,OAAO;AACzC,YAAMC,IAAWD,EAAG,MAAM,WAAcA,EAAG;AAC3C,MAAI,OAAOC,EAAQ,OAAW,YAAY,OAAOA,EAAQ,QAAY,YACnEF,EAAS,KAAKE,CAAuC;AAAA,IAEzD;AAEF,SAAOF;AACT;AAEA,SAASG,EAAiBC,GAA6B;AACrD,QAAMC,IAAKD,EAAS,QAAQ,IAAI,cAAc,KAAK;AACnD,SAAOC,EAAG,SAAS,sBAAsB,KAAKA,EAAG,SAAS,mBAAmB;AAC/E;AAEA,eAAeC,GAA0BF,GAAoBG,GAAoD;AAC/G,QAAMP,IAAgC,CAAA,GAChCQ,IAAuD;AAAA,IAC3D,SAAS,CAACC,MAAuB;AAC/B,YAAMC,IAAaC,EAAkBF,CAA2C;AAChF,MAAI,CAACC,KAAcA,EAAW,SAAS,aAEvCV,EAAS,KAAK,GAAGF,EAA4BY,EAAW,KAAK,QAAQ,CAAC;AAAA,IACxE;AAAA,EAAA;AAEF,SAAIH,MAAW,WAAWC,EAAK,SAASD,IACxC,MAAMK,EAAcR,GAAUI,CAAI,GAC3BR;AACT;AAEA,eAAsBa,GACpBC,GACAC,GACAR,GAC8B;AAC9B,QAAMS,IAAMC,EAAqB,oBAAoBF,CAAS,GAExDG,IAAyB;AAAA,IAC7B,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAA;AAAA,IAC3B,MAAM,KAAK,UAAUJ,CAAO;AAAA,EAAA;AAE9B,EAAIP,MAAW,WAAWW,EAAU,SAASX;AAC7C,QAAMH,IAAW,MAAM,MAAMY,GAAKE,CAAS;AAE3C,MAAI,CAACd,EAAS;AACZ,UAAM,IAAI,MAAM,QAAQA,EAAS,MAAM,KAAKA,EAAS,UAAU,EAAE;AAGnE,MAAID,EAAiBC,CAAQ;AAC3B,WAAOE,GAA0BF,GAAUG,CAAM;AAGnD,QAAMY,IAAO,MAAMf,EAAS,KAAA;AAC5B,MAAI,CAACe,EAAM,QAAO,CAAA;AAClB,MAAI;AACF,WAAOC,EAAiC,KAAK,MAAMD,CAAI,CAAC;AAAA,EAC1D,QAAQ;AACN,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AACF;AAEA,eAAeE,GAA2BjB,GAAoBG,GAA+C;AAC3G,QAAMe,IAAyB,CAAA;AAC/B,MAAIC,IAAoC;AAExC,QAAMf,IAAuD;AAAA,IAC3D,SAAS,CAACC,MAAuB;AAC/B,YAAMC,IAAaC,EAAkBF,CAA2C;AAChF,UAAKC,GAEL;AAAA,YAAIA,EAAW,SAAS,cAAcA,EAAW,MAAM;AACrD,gBAAMc,IAAOd,EAAW,KAAK;AAC7B,cAAI,OAAOc,KAAS,UAAU;AAC5B,YAAAD,IAAe,EAAE,MAAAC,GAAM,UAAU,GAAC;AAClC,kBAAMC,IAAYf,EAAW,KAAK;AAClC,YAAI,OAAOe,KAAc,aAAUF,EAAa,YAAYE,IAC5DH,EAAO,KAAKC,CAAY;AAAA,UAC1B;AAAA,QACF;AAEA,QAAIb,EAAW,SAAS,aAAaa,KACnCA,EAAa,SAAS,KAAK,GAAGzB,EAA4BY,EAAW,KAAK,QAAQ,CAAC;AAAA;AAAA,IAEvF;AAAA,EAAA;AAEF,SAAIH,MAAW,WAAWC,EAAK,SAASD,IACxC,MAAMK,EAAcR,GAAUI,CAAI,GAE3Bc;AACT;AAEA,eAAsBI,GACpBZ,GACAC,GACAR,GACyB;AACzB,QAAMS,IAAMC,EAAqB,qBAAqBF,CAAS,GAEzDG,IAAyB;AAAA,IAC7B,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAA;AAAA,IAC3B,MAAM,KAAK,UAAUJ,CAAO;AAAA,EAAA;AAE9B,EAAIP,MAAW,WAAWW,EAAU,SAASX;AAC7C,QAAMH,IAAW,MAAM,MAAMY,GAAKE,CAAS;AAE3C,MAAI,CAACd,EAAS;AACZ,UAAM,IAAI,MAAM,QAAQA,EAAS,MAAM,KAAKA,EAAS,UAAU,EAAE;AAGnE,MAAID,EAAiBC,CAAQ;AAC3B,WAAOiB,GAA2BjB,GAAUG,CAAM;AAGpD,QAAMY,IAAO,MAAMf,EAAS,KAAA;AAC5B,MAAI,CAACe,EAAM,QAAO,CAAA;AAClB,MAAI;AACF,WAAOQ,EAAkC,KAAK,MAAMR,CAAI,CAAC;AAAA,EAC3D,QAAQ;AACN,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AACF;AC7IO,SAASS,EAAkBC,GAA0C;AAC1E,QAAM,EAAE,SAAA3B,GAAS,OAAA4B,GAAO,cAAAC,GAAc,SAAAC,GAAS,aAAAC,GAAa,YAAAC,MAAeL,GACrEM,IAAON,EAAQ,MACfO,IAAUP,EAAQ;AAGxB,MAAIK,GAAY;AACd,UAAMG,IAAU,SAAS,cAAc,KAAK;AAC5C,WAAAA,EAAQ,YAAY,mDAEpBA,EAAQ,YAAYC,EAAaJ,EAAWhC,GAAS4B,CAAK,CAAC,GAC3DO,EAAQ,iBAAiB,SAAS,CAACE,MAAM;AACvC,MAAKA,EAAE,OAAuB,QAAQ,qBAAqB,KACtDA,EAAE,OAAuB,QAAQ,gCAAgC,KACtEP,EAAQ9B,CAAO;AAAA,IACjB,CAAC,GACMmC;AAAA,EACT;AAEA,QAAMG,IAAO,SAAS,cAAc,SAAS;AAE7C,EAAAA,EAAK,YAAY,iDACjBA,EAAK,aAAa,QAAQ,UAAU,GACpCA,EAAK,QAAQ,MAAStC,EAAQ;AAG9B,QAAMuC,IAAa,SAAS,cAAc,KAAK;AAE/C,MADAA,EAAW,YAAY,mEACnBvC,EAAQ,YAAYwC,EAAexC,EAAQ,QAAQ,GAAG;AACxD,UAAMyC,IAAM,SAAS,cAAc,KAAK;AACxC,IAAAA,EAAI,YAAY,iCAChBA,EAAI,MAAMzC,EAAQ,UAClByC,EAAI,MAAMzC,EAAQ,MAClByC,EAAI,UAAU,QACdC,GAAqBD,CAAG,GACxBF,EAAW,YAAYE,CAAG;AAAA,EAC5B;AAGA,MAAIZ,MAAiB,WAAW7B,EAAQ,mBAAmBA,EAAQ,kBAAkB,GAAG;AACtF,UAAM2C,IAAQ,SAAS,cAAc,MAAM;AAC3C,IAAAA,EAAM,YAAY,iEAClBA,EAAM,cAAc,IAAIC,GAAc5C,EAAQ,eAAe,CAAC,IAC9DuC,EAAW,YAAYI,CAAK;AAAA,EAC9B;AAEA,EAAAL,EAAK,YAAYC,CAAU;AAG3B,QAAMM,IAAO,SAAS,cAAc,KAAK;AAIzC,MAHAA,EAAK,YAAY,2DAGb7C,EAAQ,OAAO;AACjB,UAAM8C,IAAU,SAAS,cAAc,KAAK;AAC5C,IAAAA,EAAQ,YAAY,6DACpBA,EAAQ,cAAc9C,EAAQ,OAC9B6C,EAAK,YAAYC,CAAO;AAAA,EAC1B;AAGA,QAAMC,IAAS,SAAS,cAAc,KAAK;AAM3C,MALAA,EAAO,YAAY,2DACnBA,EAAO,cAAc/C,EAAQ,MAC7B6C,EAAK,YAAYE,CAAM,GAGnB/C,EAAQ,UAAU,QAAQA,EAAQ,SAAS,GAAG;AAChD,UAAMgD,IAAW,SAAS,cAAc,KAAK;AAG7C,QAFAA,EAAS,YAAY,+DACrBA,EAAS,YAAYC,GAAwBjD,EAAQ,MAAM,CAAC,GACxDA,EAAQ,eAAe,MAAM;AAC/B,YAAMkD,IAAQ,SAAS,cAAc,MAAM;AAC3C,MAAAA,EAAM,YAAY,2EAClBA,EAAM,cAAc,KAAKlD,EAAQ,WAAW,KAC5CgD,EAAS,YAAYE,CAAK;AAAA,IAC5B;AACA,IAAAL,EAAK,YAAYG,CAAQ;AAAA,EAC3B;AAGA,QAAMG,IAAiB,SAAS,cAAc,KAAK;AAGnD,MAFAA,EAAe,YAAY,6DAEvBnD,EAAQ,iBAAiBA,EAAQ,kBAAkBA,EAAQ,UACzD6B,MAAiB,oBAAoB,CAACA,IAAc;AACtD,UAAMuB,IAAW,SAAS,cAAc,MAAM;AAC9C,IAAAA,EAAS,YAAY,+EACrBA,EAAS,cAAcC,EAAYrD,EAAQ,eAAekC,CAAO,GACjEiB,EAAe,YAAYC,CAAQ;AAAA,EACrC;AAGF,MAAIpD,EAAQ,OAAO;AACjB,UAAMsD,IAAU,SAAS,cAAc,MAAM;AAC7C,IAAAA,EAAQ,YAAY,6EACpBA,EAAQ,cAAcD,EAAYrD,EAAQ,OAAOkC,CAAO,GACxDiB,EAAe,YAAYG,CAAO;AAAA,EACpC;AAEA,EAAAT,EAAK,YAAYM,CAAc,GAC/Bb,EAAK,YAAYO,CAAI;AAGrB,QAAMU,IAAM,SAAS,cAAc,QAAQ;AAY3C,MAXAA,EAAI,YAAY,yDAChBA,EAAI,OAAO,UACXA,EAAI,cAActB,GAAM,YAAY,QACpCsB,EAAI,iBAAiB,SAAS,CAAClB,MAAM;AACnC,IAAAA,EAAE,eAAA,GACFA,EAAE,gBAAA,GACFP,EAAQ9B,CAAO;AAAA,EACjB,CAAC,GACDsC,EAAK,YAAYiB,CAAG,GAGhBvD,EAAQ,YAAY,IAAO;AAC7B,UAAMwD,IAAM,SAAS,cAAc,KAAK;AACxC,IAAAA,EAAI,YAAY,2BAChBA,EAAI,cAAcvB,GAAM,mBAAmB,gBAC3CK,EAAK,YAAYkB,CAAG;AAAA,EACtB,WAAWxD,EAAQ,UAAU;AAC3B,UAAMyD,IAAWzD,EAAQ,UACnB0D,IAAUC,GAAsB;AAAA,MACpC,SAAS;AAAA,MACT,OAAO1B,GAAM,mBAAmB;AAAA,MAChC,UAAU,CAAC2B,MAAa;AACtB,QAAA7B,EAAY,EAAE,KAAK/B,EAAQ,KAAK,UAAA4D,GAAU,UAAAH,GAAU;AAAA,MACtD;AAAA,IAAA,CACD;AACD,IAAAC,EAAQ,UAAU,IAAI,oBAAoB,GAC1CpB,EAAK,YAAYoB,CAAO;AAAA,EAC1B;AAGA,SAAApB,EAAK,iBAAiB,SAAS,CAACD,MAAM;AACpC,IAAKA,EAAE,OAAuB,QAAQ,qBAAqB,KACtDA,EAAE,OAAuB,QAAQ,gCAAgC,KACjEA,EAAE,OAAuB,QAAQ,gCAAgC,KACtEP,EAAQ9B,CAAO;AAAA,EACjB,CAAC,GAEMsC;AACT;ACnJO,SAASuB,EAAkBlC,GAA0C;AAC1E,QAAMmC,IAAO,SAAS,cAAc,KAAK;AACzC,EAAAA,EAAK,YAAY,uBACjBA,EAAK,aAAa,QAAQ,MAAM,GAChCA,EAAK,aAAa,cAAcnC,EAAQ,MAAM,4BAA4B,kBAAkB,GAExFA,EAAQ,WACVmC,EAAK,MAAM,YAAY,4BAA4B,OAAOnC,EAAQ,OAAO,CAAC;AAG5E,WAASoC,IAAI,GAAGA,IAAIpC,EAAQ,SAAS,QAAQoC,KAAK;AAEhD,UAAMC,IAA+B;AAAA,MACnC,SAFcrC,EAAQ,SAASoC,CAAC;AAAA,MAGhC,OAAOA;AAAA,MACP,SAASpC,EAAQ;AAAA,MACjB,aAAaA,EAAQ;AAAA,IAAA;AAEvB,IAAIA,EAAQ,SAAS,WAAWqC,EAAS,OAAOrC,EAAQ,OACpDA,EAAQ,iBAAiB,WAAWqC,EAAS,eAAerC,EAAQ,eACpEA,EAAQ,eAAe,WAAWqC,EAAS,aAAarC,EAAQ;AACpE,UAAMW,IAAOZ,EAAkBsC,CAAQ;AACvC,IAAAF,EAAK,YAAYxB,CAAI;AAAA,EACvB;AAEA,MAAIX,EAAQ,SAAS,WAAW,GAAG;AACjC,UAAMsC,IAAQ,SAAS,cAAc,KAAK;AAC1C,IAAAA,EAAM,YAAY,wBAClBA,EAAM,cAActC,EAAQ,MAAM,qBAAqB,8BACvDmC,EAAK,YAAYG,CAAK;AAAA,EACxB;AAEA,SAAOH;AACT;AClCA,IAAII,KAA4B;AAEzB,SAASC,GAAgBxC,GAAwC;AACtE,QAAMyC,IAAaF,MACbG,IAAY,SAAS,cAAc,KAAK;AAG9C,MAFAA,EAAU,YAAY,yBAElB1C,EAAQ,OAAO,WAAW,GAAG;AAC/B,UAAMsC,IAAQ,SAAS,cAAc,KAAK;AAC1C,WAAAA,EAAM,YAAY,wBAClBA,EAAM,cAActC,EAAQ,MAAM,qBAAqB,8BACvD0C,EAAU,YAAYJ,CAAK,GACpBI;AAAA,EACT;AAGA,QAAMC,IAAS,SAAS,cAAc,KAAK;AAC3C,EAAAA,EAAO,YAAY,uBACnBA,EAAO,aAAa,QAAQ,SAAS;AAErC,QAAMC,IAA4B,CAAA,GAC5BC,IAAwB,CAAA,GAExBC,IAAmB,CAACC,MAAuE;AAC/F,UAAMC,IAA0D;AAAA,MAC9D,UAAUD,EAAM;AAAA,MAChB,SAAS/C,EAAQ;AAAA,MACjB,aAAaA,EAAQ;AAAA,IAAA;AAEvB,WAAIA,EAAQ,SAAS,WAAWgD,EAAS,OAAOhD,EAAQ,OACpDA,EAAQ,iBAAiB,WAAWgD,EAAS,eAAehD,EAAQ,eACpEA,EAAQ,eAAe,WAAWgD,EAAS,aAAahD,EAAQ,aAC7DgD;AAAA,EACT,GAEMC,IAAc,CAAChD,MAAwB;AAC3C,aAASiD,IAAI,GAAGA,IAAIN,EAAK,QAAQM,KAAK;AACpC,YAAMC,IAAWD,MAAMjD;AACvB,MAAA2C,EAAKM,CAAC,EAAG,UAAU,OAAO,8BAA8BC,CAAQ,GAChEP,EAAKM,CAAC,EAAG,aAAa,iBAAiB,OAAOC,CAAQ,CAAC,GACvDP,EAAKM,CAAC,EAAG,WAAWC,IAAW,IAAI;AAAA,IACrC;AAGA,UAAMJ,IAAQ/C,EAAQ,OAAOC,CAAK,GAC5BmD,IAAQP,EAAO5C,CAAK;AAC1B,IAAAmD,EAAM,YAAY;AAClB,UAAMjB,IAAOD,EAAkBY,EAAiBC,CAAK,CAAC;AACtD,IAAAK,EAAM,YAAYjB,CAAI;AAGtB,aAASe,IAAI,GAAGA,IAAIL,EAAO,QAAQK,KAAK;AACtC,YAAMC,IAAWD,MAAMjD;AACvB,MAAA4C,EAAOK,CAAC,EAAG,MAAM,UAAUC,IAAW,KAAK,QAC3CN,EAAOK,CAAC,EAAG,WAAWC,IAAW,IAAI;AAAA,IACvC;AAAA,EACF;AAEA,WAASf,IAAI,GAAGA,IAAIpC,EAAQ,OAAO,QAAQoC,KAAK;AAC9C,UAAMW,IAAQ/C,EAAQ,OAAOoC,CAAC,GACxBiB,IAAQ,sBAAsBZ,CAAU,IAAIL,CAAC,IAC7CkB,IAAU,wBAAwBb,CAAU,IAAIL,CAAC,IAGjDmB,IAAM,SAAS,cAAc,QAAQ;AAC3C,IAAAA,EAAI,YAAY,sBAChBA,EAAI,OAAO,UACXA,EAAI,KAAKF,GACTE,EAAI,cAAcR,EAAM,MACxBQ,EAAI,aAAa,QAAQ,KAAK,GAC9BA,EAAI,aAAa,iBAAiBD,CAAO,GACzCC,EAAI,aAAa,iBAAiB,OAAOnB,MAAM,CAAC,CAAC,GACjDmB,EAAI,WAAWnB,MAAM,IAAI,IAAI,IACzBA,MAAM,KAAGmB,EAAI,UAAU,IAAI,4BAA4B,GAE3DA,EAAI,iBAAiB,SAAS,MAAMN,EAAYb,CAAC,CAAC,GAClDmB,EAAI,iBAAiB,WAAW,CAAC7C,MAAqB;AACpD,UAAI8C,IAAO;AACX,MAAI9C,EAAE,QAAQ,gBAAgBA,EAAE,QAAQ,cACtC8C,KAAQpB,IAAI,KAAKpC,EAAQ,OAAO,SACvBU,EAAE,QAAQ,eAAeA,EAAE,QAAQ,YAC5C8C,KAAQpB,IAAI,IAAIpC,EAAQ,OAAO,UAAUA,EAAQ,OAAO,SAC/CU,EAAE,QAAQ,SACnB8C,IAAO,IACE9C,EAAE,QAAQ,UACnB8C,IAAOxD,EAAQ,OAAO,SAAS,IAE7BwD,KAAQ,MACV9C,EAAE,eAAA,GACFuC,EAAYO,CAAI,GAChBZ,EAAKY,CAAI,EAAG,MAAA;AAAA,IAEhB,CAAC,GAEDZ,EAAK,KAAKW,CAAG,GACbZ,EAAO,YAAYY,CAAG;AAGtB,UAAMH,IAAQ,SAAS,cAAc,KAAK;AAC1C,IAAAA,EAAM,YAAY,4BAClBA,EAAM,KAAKE,GACXF,EAAM,aAAa,QAAQ,UAAU,GACrCA,EAAM,aAAa,mBAAmBC,CAAK,GAC3CD,EAAM,WAAWhB,MAAM,IAAI,IAAI,IAC3BA,MAAM,MAAGgB,EAAM,MAAM,UAAU,SAEnCP,EAAO,KAAKO,CAAK;AAAA,EACnB;AAEA,EAAAV,EAAU,YAAYC,CAAM;AAG5B,QAAMc,IAAaZ,EAAO,CAAC,GACrBa,IAAYxB,EAAkBY,EAAiB9C,EAAQ,OAAO,CAAC,CAAE,CAAC;AACxE,EAAAyD,EAAW,YAAYC,CAAS;AAEhC,aAAWN,KAASP,EAAQ,CAAAH,EAAU,YAAYU,CAAK;AAEvD,SAAOV;AACT;AC3HA,SAASiB,EAAgBC,GAAqC;AAC5D,MAAI,CAACA,KAAO,OAAOA,KAAQ,SAAU,QAAO;AAC5C,QAAMC,IAAMD;AACZ,MAAI,OAAOC,EAAI,OAAW,YAAY,OAAOA,EAAI,QAAY,YAAY,OAAOA,EAAI,OAAW;AAC7F,WAAO;AAGT,QAAMC,IAAyB;AAAA,IAC7B,KAAKD,EAAI;AAAA,IACT,MAAMA,EAAI;AAAA,IACV,KAAKA,EAAI;AAAA,EAAK,GAGVE,IAAWF,EAAI;AACrB,EAAI,OAAOE,KAAa,aAAUD,EAAO,WAAWC;AACpD,QAAMC,IAAQH,EAAI;AAClB,EAAI,OAAOG,KAAU,aAAUF,EAAO,QAAQE;AAC9C,QAAMC,IAAgBJ,EAAI;AAC1B,EAAI,OAAOI,KAAkB,aAAUH,EAAO,gBAAgBG;AAC9D,QAAMC,IAAkBL,EAAI;AAC5B,EAAI,OAAOK,KAAoB,aAAUJ,EAAO,kBAAkBI;AAClE,QAAMC,IAAQN,EAAI;AAClB,EAAI,OAAOM,KAAU,aAAUL,EAAO,QAAQK;AAC9C,QAAMC,IAASP,EAAI;AACnB,EAAI,OAAOO,KAAW,aAAUN,EAAO,SAASM;AAChD,QAAMC,IAAcR,EAAI;AACxB,EAAI,OAAOQ,KAAgB,aAAUP,EAAO,cAAcO;AAC1D,QAAMvC,IAAW+B,EAAI;AACrB,EAAI,OAAO/B,KAAa,aAAUgC,EAAO,WAAWhC;AACpD,QAAMwC,IAAUT,EAAI;AACpB,SAAI,OAAOS,KAAY,cAAWR,EAAO,UAAUQ,IAE5CR;AACT;AAEA,SAASS,GAAgBX,GAAoC;AAC3D,MAAI,CAACA,KAAO,OAAOA,KAAQ,SAAU,QAAO;AAC5C,QAAMC,IAAMD,GACNY,IAAQX,EAAI,OACZY,IAAOZ,EAAI;AACjB,MAAI,OAAOW,KAAU,YAAY,OAAOC,KAAS,SAAU,QAAO;AAClE,QAAMC,IAAwB,EAAE,OAAAF,GAAO,MAAAC,EAAA;AACvC,SAAIZ,EAAI,YAAe,WAAWa,EAAO,UAAUb,EAAI,UAChDa;AACT;AAEA,MAAMC,IAAwD;AAAA,EAC5D,aAAa,CAAC,EAAE,SAAAC,GAAS,eAAAC,GAAe,SAAAC,QAAc;AACpD,UAAM3C,IAAO,SAAS,cAAc,KAAK;AACzC,IAAAA,EAAK,YAAY,uBACjBA,EAAK,aAAa,QAAQ,MAAM;AAEhC,UAAM4C,IAAUH,EAAQ,OAAQ;AAChC,IAAI,OAAOG,KAAY,YAAY,OAAO,SAASA,CAAO,KAAKA,IAAU,KACvE5C,EAAK,MAAM,YAAY,4BAA4B,OAAO4C,CAAO,CAAC;AAGpE,eAAWC,KAAWJ,EAAQ,YAAY,CAAA,GAAI;AAC5C,YAAMK,IAAWJ,EAAcG,CAAO;AACtC,MAAIC,KAAU9C,EAAK,YAAY8C,CAAQ;AAAA,IACzC;AAEA,QAAI9C,EAAK,SAAS,WAAW,GAAG;AAC9B,YAAMG,IAAQ,SAAS,cAAc,KAAK;AAC1C,MAAAA,EAAM,YAAY,wBAClBA,EAAM,cAAcwC,EAAQ,KAAK,mBACjC3C,EAAK,YAAYG,CAAK;AAAA,IACxB;AAEA,WAAOH;AAAA,EACT;AAAA,EAEA,aAAa,CAAC,EAAE,SAAAyC,GAAS,SAAAE,QAAc;AACrC,UAAMI,IAAcN,EAAQ,OAAQ,WAAcA,EAAQ,OACpDvG,IAAUsF,EAAgBuB,CAAU;AAC1C,QAAI,CAAC7G,EAAS,QAAO;AAErB,UAAM8G,IAAWP,EAAQ,OAAQ,OAC3B3E,IAAQ,OAAOkF,KAAa,YAAY,OAAO,SAASA,CAAQ,IAAIA,IAAW,GAC/EC,IAAkBR,EAAQ,OAAQ,cAClC1E,IACJkF,MAAoB,oBAAoBA,MAAoB,UAAUA,IAAkBN,EAAQ,cAE5F9E,IAAyD;AAAA,MAC7D,SAAA3B;AAAA,MACA,OAAA4B;AAAA,MACA,SAAS6E,EAAQ;AAAA,MACjB,aAAaA,EAAQ;AAAA,MACrB,MAAMA,EAAQ;AAAA,IAAA;AAEhB,WAAI5E,MAAiB,WAAWF,EAAQ,eAAeE,IACnD4E,EAAQ,eAAe,WAAW9E,EAAQ,aAAa8E,EAAQ,aAC/DA,EAAQ,YAAY,WAAW9E,EAAQ,UAAU8E,EAAQ,UACtD/E,EAAkBC,CAAO;AAAA,EAClC;AAAA,EAEA,WAAW,CAAC,EAAE,SAAA4E,GAAS,SAAAE,QAAc;AACnC,UAAMO,IAAYT,EAAQ,OAAQ;AAClC,QAAI,CAAC,MAAM,QAAQS,CAAS,EAAG,QAAO;AACtC,UAAM5F,IAAyB,CAAA;AAE/B,eAAW6F,KAASD,GAAW;AAC7B,UAAI,CAACC,KAAS,OAAOA,KAAU,SAAU;AACzC,YAAMzB,IAAMyB;AACZ,UAAI,OAAOzB,EAAI,QAAY,SAAU;AAErC,YAAM1F,IAA6B,CAAA;AACnC,UAAI,MAAM,QAAQ0F,EAAI,QAAW;AAC/B,mBAAW0B,KAAc1B,EAAI,UAAa;AACxC,gBAAMhF,IAAa8E,EAAgB4B,CAAU;AAC7C,UAAI1G,KAAYV,EAAS,KAAKU,CAAU;AAAA,QAC1C;AAGF,YAAMkE,IAAsB;AAAA,QAC1B,MAAMc,EAAI;AAAA,QACV,UAAA1F;AAAA,MAAA;AAEF,MAAI,OAAO0F,EAAI,aAAiB,aAAUd,EAAM,YAAYc,EAAI,YAChEpE,EAAO,KAAKsD,CAAK;AAAA,IACnB;AAEA,UAAM/C,IAAqD;AAAA,MACzD,QAAAP;AAAA,MACA,SAASqF,EAAQ;AAAA,MACjB,aAAaA,EAAQ;AAAA,MACrB,MAAMA,EAAQ;AAAA,IAAA;AAEhB,WAAIA,EAAQ,iBAAiB,WAAW9E,EAAQ,eAAe8E,EAAQ,eACnEA,EAAQ,eAAe,WAAW9E,EAAQ,aAAa8E,EAAQ,aAC5DtC,GAAgBxC,CAAO;AAAA,EAChC;AAAA,EAEA,YAAY,CAAC,EAAE,SAAA4E,GAAS,SAAAE,QAAc;AACpC,UAAMxC,IAAQ,SAAS,cAAc,KAAK;AAC1C,IAAAA,EAAM,YAAY;AAClB,UAAMkD,IAAUZ,EAAQ,OAAQ;AAChC,WAAAtC,EAAM,cAAc,OAAOkD,KAAY,WAAWA,IAAUV,EAAQ,KAAK,mBAClExC;AAAA,EACT;AAAA,EAEA,iBAAiB,CAAC,EAAE,SAAAsC,GAAS,SAAAE,QAAc;AACzC,UAAMW,IAAMb,EAAQ,OAAQ,KACtB9C,IAAW8C,EAAQ,OAAQ;AACjC,QAAI,OAAOa,KAAQ,YAAY,OAAO3D,KAAa,SAAU,QAAO;AAEpE,UAAM4D,IAAS,SAAS,cAAc,QAAQ;AAC9C,IAAAA,EAAO,YAAY,oDACnBA,EAAO,OAAO;AACd,UAAMC,IAAQf,EAAQ,OAAQ;AAC9B,WAAAc,EAAO,cAAc,OAAOC,KAAU,WAAWA,IAAQb,EAAQ,KAAK,iBACtEY,EAAO,iBAAiB,SAAS,CAAChF,MAAM;AACtC,MAAAA,EAAE,eAAA,GACFA,EAAE,gBAAA,GACFoE,EAAQ,YAAY,EAAE,KAAAW,GAAK,UAAU,GAAG,UAAA3D,GAAU;AAAA,IACpD,CAAC,GACM4D;AAAA,EACT;AAAA,EAEA,cAAc,CAAC,EAAE,SAAAd,GAAS,SAAAE,QAAc;AACtC,UAAMtE,IAAU,SAAS,cAAc,KAAK;AAC5C,IAAAA,EAAQ,YAAY;AACpB,UAAMoF,IAAUhB,EAAQ,OAAQ;AAChC,QAAI,CAAC,MAAM,QAAQgB,CAAO,KAAK,CAACd,EAAQ,SAAU,QAAOtE;AAEzD,eAAWoD,KAAOgC,GAAS;AACzB,UAAI,CAAChC,KAAO,OAAOA,KAAQ,SAAU;AACrC,YAAMiC,IAAYjC,GACZ+B,IAAQE,EAAU,OAClBnB,IAASH,GAAgBsB,EAAU,MAAS;AAClD,UAAI,OAAOF,KAAU,YAAY,CAACjB,EAAQ;AAE1C,YAAMgB,IAAS,SAAS,cAAc,QAAQ;AAC9C,MAAAA,EAAO,YAAY,+BACnBA,EAAO,OAAO,UACdA,EAAO,cAAcC,GACrBD,EAAO,iBAAiB,SAAS,CAAChF,MAAM;AACtC,QAAAA,EAAE,eAAA,GACFA,EAAE,gBAAA,GACFoE,EAAQ,WAAWJ,CAAM;AAAA,MAC3B,CAAC,GACDlE,EAAQ,YAAYkF,CAAM;AAAA,IAC5B;AACA,WAAOlF;AAAA,EACT;AACF,GAEasF,IAA0F,CAAC;AAAA,EACtG,SAAAlB;AAAA,EACA,eAAAC;AACF,MAAM;AAIJ,MAAI,CAACD,EAAQ,YAAYA,EAAQ,SAAS,WAAW;AACnD,WAAO;AAET,QAAMpE,IAAU,SAAS,cAAc,KAAK;AAC5C,aAAWwE,KAAWJ,EAAQ,UAAU;AACtC,UAAMK,IAAWJ,EAAcG,CAAO;AACtC,IAAIC,KAAUzE,EAAQ,YAAYyE,CAAQ;AAAA,EAC5C;AACA,SAAOzE;AACT;AAEO,SAASuF,KAA0D;AACxE,SAAO,EAAE,GAAGpB,EAAA;AACd;AAEO,SAASqB,GACdC,GACAnB,GACAoB,IAAWvB,GACXwB,IAAuEL,GAC1D;AACb,SAAOM,EAAyB;AAAA,IAC9B,MAAAH;AAAA,IACA,SAAAnB;AAAA,IACA,UAAAoB;AAAA,IACA,oBAAoB;AAAA,IACpB,iBAAAC;AAAA,EAAA,CACD;AACH;ACtOO,MAAME,IAA6B;AAAA,EACxC,0BAA0B;AAAA,EAC1B,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,aAAa;AACf,GCPaC,KAA6B;AAAA,EACxC,0BAA0B;AAAA,EAC1B,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,aAAa;AACf;ACLA,SAASC,GAAgBC,GAAyB;AAChD,SAAKA,IACEA,EAAO,cAAc,MAAM,GAAG,EAAE,CAAC,KAAK,OADzB;AAEtB;AAEO,SAASC,GAAoBD,GAA6B;AAC/D,SAAQD,GAAgBC,CAAM,MACvB,OACIF,KAEAD;AAEb;ACHA,MAAMK,KAAuBC,EAAS;AAAA,EACpC,KAAKC,EAAE;AAAA,EACP,MAAMA,EAAE;AAAA,EACR,UAAUA,EAAE,EAAS,IAAA,EAAM,SAAA;AAAA,EAC3B,OAAOA,EAAE,EAAS,SAAA;AAAA,EAClB,eAAeA,EAAE,EAAS,SAAA;AAAA,EAC1B,iBAAiBC,EAAE,EAAS,SAAA;AAAA,EAC5B,KAAKD,EAAE,EAAS,IAAA;AAAA,EAChB,OAAOA,EAAE,EAAS,SAAA;AAAA,EAClB,QAAQC,EAAE,EAAS,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAA;AAAA,EACjC,aAAaA,EAAE,EAAS,MAAM,YAAA,EAAc,SAAA;AAC9C,CAAC,GAEYC,KAAoBH,EAAS;AAAA,EACxC,QAAQI,EAAO,CAAC,QAAQ,UAAU,CAAC,EAAE,SAAA;AAAA,EACrC,SAASF,EAAE,EAAS,MAAM,SAAA,EAAW,SAAA;AACvC,CAAC,GAEYG,KAAoBL,EAAS;AAAA,EACxC,SAASD;AAAA,EACT,OAAOG,EAAE,EAAS,IAAA,EAAM,YAAA;AAAA,EACxB,cAAcE,EAAO,CAAC,kBAAkB,OAAO,CAAC,EAAE,SAAA;AACpD,CAAC,GAEYE,KAAwBN,EAAS;AAAA,EAC5C,KAAKC,EAAE;AAAA,EACP,OAAOA,EAAE,EAAS,SAAA;AAAA,EAClB,UAAUA,EAAE;AACd,CAAC,GAEYM,KAAqBP,EAAS;AAAA,EACzC,SAASQ;AAAAA,IACPR,EAAS;AAAA,MACP,OAAOC,EAAE;AAAA,MACT,QAAQD,EAAS;AAAA,QACf,OAAOC,EAAE;AAAA,QACT,MAAMA,EAAE;AAAA,QACR,SAASQ,EAAE,EAAU,SAAA;AAAA,MAAS,CAC/B;AAAA,IAAA,CACF;AAAA,EAAA;AAEL,CAAC,GAEYC,KAAmBV,EAAS;AAAA,EACvC,SAASC,EAAE,EAAS,SAAA;AACtB,CAAC,GAEYU,KAAgB;AAAA,EAC3B,YAAY;AAAA,IACV,aAAa;AAAA,MACX,QAAQR;AAAA,MACR,aAAa;AAAA,IAAA;AAAA,IAEf,aAAa;AAAA,MACX,QAAQE;AAAA,MACR,aAAa;AAAA,IAAA;AAAA,IAEf,iBAAiB;AAAA,MACf,QAAQC;AAAA,MACR,aAAa;AAAA,IAAA;AAAA,IAEf,cAAc;AAAA,MACZ,QAAQC;AAAA,MACR,aAAa;AAAA,IAAA;AAAA,IAEf,YAAY;AAAA,MACV,QAAQG;AAAA,MACR,aAAa;AAAA,IAAA;AAAA,EACf;AAEJ;AC9BO,MAAME,WAAsBC,EAA+B;AAAA,EAA3D,cAAA;AAAA,UAAA,GAAA,SAAA,GACL,KAAQ,mBAA2C,MACnD,KAAQ,aAAiC,MAEzC,KAAQ,QAAoBnB;AAAA,EAAA;AAAA,EAE5B,MAAgB,OAAOoB,GAA2C;AAChE,SAAK,QAAQ,KAAK,aAAaA,CAAM,GAErC,KAAK,aAAa,SAAS,cAAc,KAAK,GAC9C,KAAK,WAAW,YAAY,4BAC5B,KAAK,KAAK,YAAY,KAAK,UAAU,GAErC,KAAK,WAAWA,EAAO,KACvB,MAAM,KAAK,gBAAgBA,EAAO,GAAG,GACrC,KAAK,YAAY,IACjBC,EAAa,QAAQ;AAAA,EACvB;AAAA,EAEU,SAAS5C,GAAqC;AACtD,UAAM6C,IAAS7C,EAAQ;AACvB,IAAI,CAAC6C,KAAUA,MAAW,KAAK,aAC/B,KAAK,WAAWA,GACX,KAAK,gBAAgBA,CAAM;AAAA,EAClC;AAAA,EAEU,SAAe;AACvB,IAAI,KAAK,eACP,KAAK,WAAW,MAAM,UAAU,KAChC,KAAK,WAAW,MAAM,aAAa,wBACnC,sBAAsB,MAAM;AAC1B,MAAI,KAAK,eAAY,KAAK,WAAW,MAAM,UAAU;AAAA,IACvD,CAAC;AAAA,EAEL;AAAA,EAEU,SAAe;AAAA,EAEzB;AAAA,EAEU,YAAkB;AAC1B,SAAK,OAAA,GACD,KAAK,eACP,KAAK,WAAW,OAAA,GAChB,KAAK,aAAa;AAAA,EAEtB;AAAA;AAAA;AAAA;AAAA,EAMA,oBAAoBtJ,GAAkC;AACpD,UAAMuJ,IAAgC;AAAA,MACpC,KAAKvJ,EAAQ;AAAA,MACb,MAAMA,EAAQ;AAAA,MACd,KAAKA,EAAQ;AAAA,IAAA;AAYf,QAVIA,EAAQ,aAAa,WAAWuJ,EAAc,WAAWvJ,EAAQ,WACjEA,EAAQ,UAAU,WAAWuJ,EAAc,QAAQvJ,EAAQ,QAC3DA,EAAQ,kBAAkB,WAAWuJ,EAAc,gBAAgBvJ,EAAQ,gBAC3EA,EAAQ,oBAAoB,WAAWuJ,EAAc,kBAAkBvJ,EAAQ,kBAC/EA,EAAQ,UAAU,WAAWuJ,EAAc,QAAQvJ,EAAQ,QAC3DA,EAAQ,WAAW,WAAWuJ,EAAc,SAASvJ,EAAQ,SAC7DA,EAAQ,gBAAgB,WAAWuJ,EAAc,cAAcvJ,EAAQ,cACvEA,EAAQ,aAAa,WAAWuJ,EAAc,WAAWvJ,EAAQ,WACjEA,EAAQ,YAAY,WAAWuJ,EAAc,UAAUvJ,EAAQ,UAE/D,KAAK,OAAO,iBAAiBuJ,CAAa,MAAM,GAAO;AAE3DC,IAAAA,EAAsBxJ,EAAQ,KAAKA,EAAQ,IAAI;AAC/C,UAAMyJ,IAAY,KAAK,OAAO,SAAS,aAAa;AACpD,IAAAC,EAAS,iCAAiC;AAAA,MACxC,KAAK1J,EAAQ;AAAA,MACb,KAAKA,EAAQ;AAAA,MACb,WAAAyJ;AAAA,IAAA,CACD,GAED,KAAK,OAAO,oBAAoBzJ,EAAQ,KAAKA,EAAQ,KAAKyJ,CAAS;AAAA,EACrE;AAAA,EAEA,iBAAiBE,GAAmE;AAClFC,IAAAA,EAAgBD,EAAO,KAAKA,EAAO,QAAQ,GAC3C,KAAK,OAAO,cAAcA,CAAM,GAChCD,EAAS,+BAA+BC,CAAM,GAE9C,KAAK;AAAA,MACHE,EAAe,KAAK,oBAAoB;AAAA,QACtC,oBAAoB;AAAA,QACpB,uBAAuB,OAAO,WAAA;AAAA,QAC9B,YAAY;AAAA;AAAA,QACZ,UAAU;AAAA,QACV,YAAYF,EAAO;AAAA,QACnB,KAAKA,EAAO;AAAA,MAAA,CACb;AAAA,IAAA;AAAA,EAEL;AAAA;AAAA;AAAA;AAAA,EAMQ,SAAe;AACrB,SAAK,kBAAkB,MAAA,GACvB,KAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEA,MAAc,gBAAgBvC,GAA4B;AACxD,SAAK,OAAA,GACL,KAAK,mBAAmB,IAAI,gBAAA;AAI5B,UAAM/G,IAAS,KAAK,iBAAiB;AAErC,QAAI,CAAC,KAAK,WAAY;AACtB,SAAK,WAAW,YAAY,IAE5B,KAAK,WAAW,MAAM,UAAU;AAGhC,UAAMyJ,IAAU,SAAS,cAAc,KAAK;AAC5C,IAAAA,EAAQ,YAAY;AACpB,UAAMC,IAAU,SAAS,cAAc,KAAK;AAC5C,IAAAA,EAAQ,YAAY,0BACpBD,EAAQ,YAAYC,CAAO,GAC3B,KAAK,WAAW,YAAYD,CAAO;AAEnC,UAAMjJ,IAAiC;AAAA,MACrC,eAAe,KAAK,OAAO;AAAA,IAAA,GAGvBmJ,IAAY,OAAO,WAAA,GACnBC,IAAa,KAAK,IAAA;AAExB,SAAK;AAAA,MACHC,EAAiB,KAAK,oBAAoB;AAAA,QACxC,UAAU;AAAA,QACV,YAAYF;AAAA,QACZ,QAAQ;AAAA,MAAA,CACT;AAAA,IAAA;AAGH,QAAI;AAEF,YAAMG,IAAoD;AAAA,QACxD,YAAY,KAAK,OAAO;AAAA,QACxB,YAAY,KAAK,OAAO,SAAS,aAAa;AAAA,QAC9C,gBAAgB,KAAK,OAAO,SAAS,aAAa;AAAA,QAClD,KAAA/C;AAAA,MAAA;AAEF,MAAI,KAAK,OAAO,WAAW,WAAW+C,EAAO,SAAS,KAAK,OAAO;AAClE,YAAMrK,IAAW,MAAMa,GAAqBwJ,GAAQtJ,GAAWR,CAAM;AAErE,UAAI,CAAC,KAAK,WAAY;AAItB,UAHA,KAAK,WAAW,YAAY,IAGxBP,EAAS,SAAS;AACpB,YAAI;AACF,gBAAMsK,IAAOtK,EAAS,IAAI,CAACuK,MAAMA,EAAE,GAAG,GAChCjJ,IAAS,MAAMI;AAAA,YACnB;AAAA,cACE,YAAY,KAAK,OAAO;AAAA,cACxB,YAAY,KAAK,OAAO,SAAS,aAAa;AAAA,cAC9C,gBAAgB,KAAK,OAAO,SAAS,aAAa;AAAA,cAClD,MAAA4I;AAAA,YAAA;AAAA,YAEFvJ;AAAA,YACAR;AAAA,UAAA;AAGF,cAAIe,EAAO,SAAS,KAAK,KAAK,YAAY;AACxC,kBAAMkJ,IAAa,KAAK,iBAAiBlJ,CAAM,GACzCmJ,IAAiB,KAAK,cAAcD,CAAU;AACpD,iBAAK,WAAW,YAAYC,CAAc,GAE1CC,EAAa,QAAQ,GACrB,KAAK;AAAA,cACHC,EAAgB,KAAK,oBAAoB;AAAA,gBACvC,YAAYT;AAAA,gBACZ,YAAY,KAAK,IAAA,IAAQC;AAAA,gBACzB,aAAa7I,EAAO,OAAO,CAACsJ,GAAGC,MAAMD,IAAIC,EAAE,SAAS,QAAQ,CAAC;AAAA,gBAC7D,QAAQ;AAAA,cAAA,CACT;AAAA,YAAA,GAEH,KAAK;AAAA,cACHC,EAA2B,KAAK,oBAAoB;AAAA,gBAClD,eAAexJ,EAAO,OAAO,CAACsJ,GAAGC,MAAMD,IAAIC,EAAE,SAAS,QAAQ,CAAC;AAAA,gBAC/D,aAAaX;AAAA,gBACb,iBAAiB;AAAA,gBACjB,QAAQ;AAAA,cAAA,CACT;AAAA,YAAA;AAEH;AAAA,UACF;AAAA,QACF,QAAQ;AAAA,QAER;AAIF,UAAI,KAAK,YAAY;AACnB,cAAMa,IAAW,KAAK,mBAAmB/K,CAAQ,GAC3CgL,IAAe,KAAK,cAAcD,CAAQ;AAChD,aAAK,WAAW,YAAYC,CAAY;AAAA,MAC1C;AAEA,MAAIhL,EAAS,SAAS,KACpB0K,EAAa,QAAQ,GAGvB,KAAK;AAAA,QACHC,EAAgB,KAAK,oBAAoB;AAAA,UACvC,YAAYT;AAAA,UACZ,YAAY,KAAK,IAAA,IAAQC;AAAA,UACzB,aAAanK,EAAS;AAAA,UACtB,QAAQ;AAAA,QAAA,CACT;AAAA,MAAA,GAGH,KAAK;AAAA,QACH8K,EAA2B,KAAK,oBAAoB;AAAA,UAClD,eAAe9K,EAAS;AAAA,UACxB,aAAakK;AAAA,UACb,iBAAiB;AAAA,UACjB,QAAQ;AAAA,QAAA,CACT;AAAA,MAAA;AAAA,IAEL,SAASe,GAAK;AACZ,UAAIA,aAAe,gBAAgBA,EAAI,SAAS,aAAc;AAqB9D,UAnBArB,EAAS,wBAAwB;AAAA,QAC/B,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,SAASsB,EAAsB,KAAK,OAAO,MAAM;AAAA,MAAA,CAClD,GAED,KAAK;AAAA,QACHC,EAAiB,KAAK,oBAAoB;AAAA,UACxC,YAAYjB;AAAA,UACZ,YAAY;AAAA,UACZ,eAAee,aAAe,QAAQA,EAAI,UAAU,OAAOA,CAAG;AAAA,UAC9D,QAAQ;AAAA,QAAA,CACT;AAAA,MAAA,GAOC,KAAK,YAAY;AACnB,aAAK,WAAW,YAAY;AAC5B,cAAMG,IAAU,SAAS,cAAc,KAAK;AAC5C,QAAAA,EAAQ,YAAY,wBACpBA,EAAQ,MAAM,UAAU;AACxB,cAAMC,IAAQ,SAAS,cAAc,MAAM;AAC3C,QAAAA,EAAM,cAAc,KAAK,OAAO,QAAQ,WAAW,IAAI,IACnD,gCACA,oCACJD,EAAQ,YAAYC,CAAK;AACzB,cAAMC,IAAW,SAAS,cAAc,QAAQ;AAChD,QAAAA,EAAS,cAAc,KAAK,OAAO,QAAQ,WAAW,IAAI,IAAI,gBAAgB,aAC9EA,EAAS,MAAM,UACb,4IACFA,EAAS,iBAAiB,SAAS,MAAM;AACvC,UAAK,KAAK,gBAAgB,KAAK,OAAO,GAAG;AAAA,QAC3C,CAAC,GACDF,EAAQ,YAAYE,CAAQ,GAC5B,KAAK,WAAW,YAAYF,CAAO;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aAAa9B,GAAwC;AAE3D,WAAO,EAAE,GADIhB,GAAoBgB,EAAO,MAAM,GAC5B,GAAGA,EAAO,KAAA;AAAA,EAC9B;AAAA,EAEQ,yBAAyB;AAC/B,UAAMiC,IAAe3D,GAAA;AACrB,WAAO4D,EAAoBD,GAAc,KAAK,OAAO,UAAU,QAAQ;AAAA,EACzE;AAAA,EAEQ,sBAAiD;AACvD,UAAMrJ,IAAa,KAAK,OAAO,YACzByE,IAAqC;AAAA,MACzC,SAAS,CAACzG,MAAY,KAAK,oBAAoBA,CAAuC;AAAA,MACtF,aAAa,CAAC2J,MAAW,KAAK,iBAAiBA,CAAM;AAAA,MACrD,MAAM,KAAK;AAAA,IAAA;AAEb,WAAI,KAAK,OAAO,iBAAiB,WAAWlD,EAAQ,eAAe,KAAK,OAAO,eAC3EzE,MAAe,WAAWyE,EAAQ,aAAazE,IAC/C,KAAK,OAAO,YAAY,WAAWyE,EAAQ,UAAU,KAAK,OAAO,UAC9DA;AAAA,EACT;AAAA,EAEQ,cAAcmB,GAA2B;AAC/C,UAAMC,IAAW,KAAK,uBAAA,GAChBpB,IAAU,KAAK,oBAAA,GACfqB,IAAkB,KAAK,OAAO,UAAU,mBAAmBL,GAC3D8D,IAAgB,CAACC,GAAmBC,MACxC9D,GAAmB6D,GAAWC,GAAc5D,GAAUC,CAAe,GAEjE4D,IAAW,KAAK,OAAO,UAAU;AACvC,WAAKA,IAOEA,EAAS9D,GAAMnB,GAL0C;AAAA,MAC9D,UAAAoB;AAAA,MACA,iBAAAC;AAAA,MACA,eAAAyD;AAAA,IAAA,CAEoC,IAPhBA,EAAc3D,GAAMnB,CAAO;AAAA,EAQnD;AAAA,EAEQ,mBAAmB3G,GAAuC;AAChE,UAAMD,IAAsC,CAAA,GACtC8L,IAAqB,CAAA;AAC3B,aAAS,IAAI,GAAG,IAAI7L,EAAS,QAAQ,KAAK;AACxC,YAAME,IAAUF,EAAS,CAAC,GACpB8L,IAAK,WAAW,CAAC;AACvB,MAAAD,EAAS,KAAKC,CAAE,GAChB/L,EAAS+L,CAAE,IAAI;AAAA,QACb,MAAM;AAAA,QACN,OAAO;AAAA,UACL,SAAA5L;AAAA,UACA,OAAO;AAAA,UACP,cAAc,KAAK,OAAO;AAAA,QAAA;AAAA,MAC5B;AAAA,IAEJ;AACA,WAAAH,EAAS,OAAU;AAAA,MACjB,MAAM;AAAA,MACN,OAAO;AAAA,QACL,QAAQ;AAAA,MAAA;AAAA,MAEV,UAAA8L;AAAA,IAAA,GAEK;AAAA,MACL,MAAM;AAAA,MACN,UAAA9L;AAAA,IAAA;AAAA,EAEJ;AAAA,EAEQ,iBACNuB,GAKQ;AACR,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU;AAAA,QACR,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,OAAO,EAAE,QAAAA,EAAA;AAAA,QAAO;AAAA,MAClB;AAAA,IACF;AAAA,EAEJ;AACF;AAEO,SAASyK,KAAoC;AAClD,SAAO,IAAI3C,GAAA;AACb;"}
1
+ {"version":3,"file":"simrel.js","sources":["../src/simrel/api.ts","../src/simrel/components/ProductCard.ts","../src/simrel/components/ProductGrid.ts","../src/simrel/components/GroupTabs.ts","../src/simrel/components/renderUISpec.ts","../src/simrel/locales/tr.ts","../src/simrel/locales/en.ts","../src/simrel/locales/index.ts","../src/simrel/catalog.ts","../src/simrel/index.ts"],"sourcesContent":["import { buildChatEndpointUrl } from '../common/api-paths.js';\nimport { consumeStream } from '../common/streaming.js';\nimport {\n adaptBackendEvent,\n normalizeSimilarProductsResponse,\n normalizeProductGroupingsResponse,\n} from '../common/protocol-adapter.js';\nimport type { NormalizedProduct } from '../common/protocol-adapter.js';\nimport type { StreamEvent, UIElement } from '../common/types.js';\nimport type { ChatTransportConfig } from '../common/api-paths.js';\n\nexport interface SimilarProductsRequest {\n account_id: string;\n session_id: string;\n correlation_id: string;\n sku: string;\n domain?: string;\n limit?: number;\n output_language?: string;\n}\n\nexport interface ProductGroupingsRequest {\n account_id: string;\n session_id: string;\n correlation_id: string;\n skus: string[];\n output_language?: string;\n}\n\nexport interface ProductGroup {\n name: string;\n highlight?: string;\n products: NormalizedProduct[];\n}\n\nfunction extractProductCardsFromSpec(elements: Record<string, UIElement>): NormalizedProduct[] {\n const products: NormalizedProduct[] = [];\n for (const el of Object.values(elements)) {\n if (el.type === 'ProductCard' && el.props) {\n const product = (el.props['product'] ?? el.props) as Record<string, unknown>;\n if (typeof product['sku'] === 'string' && typeof product['name'] === 'string') {\n products.push(product as unknown as NormalizedProduct);\n }\n }\n }\n return products;\n}\n\nfunction isNDJSONResponse(response: Response): boolean {\n const ct = response.headers.get('Content-Type') ?? '';\n return ct.includes('application/x-ndjson') || ct.includes('text/event-stream');\n}\n\nasync function collectProductsFromStream(response: Response, signal?: AbortSignal): Promise<NormalizedProduct[]> {\n const products: NormalizedProduct[] = [];\n const opts: import('../common/streaming.js').StreamOptions = {\n onEvent: (event: StreamEvent) => {\n const normalized = adaptBackendEvent(event as unknown as Record<string, unknown>);\n if (!normalized || normalized.type !== 'ui_spec') return;\n\n products.push(...extractProductCardsFromSpec(normalized.spec.elements));\n },\n };\n if (signal !== undefined) opts.signal = signal;\n await consumeStream(response, opts);\n return products;\n}\n\nexport async function fetchSimilarProducts(\n request: SimilarProductsRequest,\n transport: ChatTransportConfig,\n signal?: AbortSignal,\n): Promise<NormalizedProduct[]> {\n const url = buildChatEndpointUrl('similar_products', transport);\n\n const fetchInit: RequestInit = {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(request),\n };\n if (signal !== undefined) fetchInit.signal = signal;\n const response = await fetch(url, fetchInit);\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n if (isNDJSONResponse(response)) {\n return collectProductsFromStream(response, signal);\n }\n\n const text = await response.text();\n if (!text) return [];\n try {\n return normalizeSimilarProductsResponse(JSON.parse(text));\n } catch {\n throw new Error(`Invalid JSON from similar_products endpoint`);\n }\n}\n\nasync function collectGroupingsFromStream(response: Response, signal?: AbortSignal): Promise<ProductGroup[]> {\n const groups: ProductGroup[] = [];\n let currentGroup: ProductGroup | null = null;\n\n const opts: import('../common/streaming.js').StreamOptions = {\n onEvent: (event: StreamEvent) => {\n const normalized = adaptBackendEvent(event as unknown as Record<string, unknown>);\n if (!normalized) return;\n\n if (normalized.type === 'metadata' && normalized.meta) {\n const name = normalized.meta['group_name'];\n if (typeof name === 'string') {\n currentGroup = { name, products: [] };\n const highlight = normalized.meta['highlight'];\n if (typeof highlight === 'string') currentGroup.highlight = highlight;\n groups.push(currentGroup);\n }\n }\n\n if (normalized.type === 'ui_spec' && currentGroup) {\n currentGroup.products.push(...extractProductCardsFromSpec(normalized.spec.elements));\n }\n },\n };\n if (signal !== undefined) opts.signal = signal;\n await consumeStream(response, opts);\n\n return groups;\n}\n\nexport async function fetchProductGroupings(\n request: ProductGroupingsRequest,\n transport: ChatTransportConfig,\n signal?: AbortSignal,\n): Promise<ProductGroup[]> {\n const url = buildChatEndpointUrl('product_groupings', transport);\n\n const fetchInit: RequestInit = {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(request),\n };\n if (signal !== undefined) fetchInit.signal = signal;\n const response = await fetch(url, fetchInit);\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n if (isNDJSONResponse(response)) {\n return collectGroupingsFromStream(response, signal);\n }\n\n const text = await response.text();\n if (!text) return [];\n try {\n return normalizeProductGroupingsResponse(JSON.parse(text));\n } catch {\n throw new Error(`Invalid JSON from product_groupings endpoint`);\n }\n}\n","import type { NormalizedProduct } from '../../common/protocol-adapter.js';\nimport type { SimRelI18n } from '../types.js';\nimport type { PriceFormatConfig } from '../../common/price-formatter.js';\nimport { formatPrice } from '../../common/price-formatter.js';\nimport { sanitizeHtml, isSafeImageUrl } from '../../common/safe-html.js';\nimport { createQuantityStepper } from '../../common/quantity-stepper.js';\nimport { clampDiscount, addImageErrorHandler, createStarRatingElement } from '../../common/product-utils.js';\n\nexport interface ProductCardOptions {\n product: NormalizedProduct;\n index: number;\n discountType?: 'strike-through' | 'badge';\n onClick: (product: NormalizedProduct) => void;\n onAddToCart: (params: { sku: string; quantity: number; cartCode: string }) => void;\n renderCard?: (product: NormalizedProduct, index: number) => string;\n renderCardElement?: (product: NormalizedProduct, index: number) => HTMLElement | null;\n i18n?: SimRelI18n;\n pricing?: PriceFormatConfig;\n}\n\nexport function renderProductCard(options: ProductCardOptions): HTMLElement {\n const { product, index, discountType, onClick, onAddToCart, renderCard } = options;\n const i18n = options.i18n;\n const pricing = options.pricing;\n\n // Custom card element renderer (returns full HTMLElement, takes precedence)\n if (options.renderCardElement) {\n const el = options.renderCardElement(product, index);\n if (el) return el;\n }\n\n // Custom card renderer (XSS warning: raw HTML injection)\n if (renderCard) {\n const wrapper = document.createElement('div');\n wrapper.className = 'gengage-simrel-card gengage-simrel-card--custom';\n // Sanitize renderCard output to prevent XSS from user-provided renderers.\n wrapper.innerHTML = sanitizeHtml(renderCard(product, index));\n wrapper.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.gengage-simrel-atc')) return;\n if ((e.target as HTMLElement).closest('.gengage-chat-product-card-atc')) return;\n onClick(product);\n });\n return wrapper;\n }\n\n const card = document.createElement('article');\n // Intentional class coupling: reuse chat product-card classes so SimRel and chat stay visually identical.\n card.className = 'gengage-simrel-card gengage-chat-product-card';\n card.setAttribute('role', 'listitem');\n card.dataset['sku'] = product.sku;\n\n // Image\n const imgWrapper = document.createElement('div');\n imgWrapper.className = 'gengage-simrel-card-image gengage-chat-product-card-img-wrapper';\n if (product.imageUrl && isSafeImageUrl(product.imageUrl)) {\n const img = document.createElement('img');\n img.className = 'gengage-chat-product-card-img';\n img.src = product.imageUrl;\n img.alt = product.name;\n img.loading = 'lazy';\n addImageErrorHandler(img);\n imgWrapper.appendChild(img);\n }\n\n // Discount badge\n if (discountType === 'badge' && product.discountPercent && product.discountPercent > 0) {\n const badge = document.createElement('span');\n badge.className = 'gengage-simrel-badge gengage-chat-product-card-discount-badge';\n badge.textContent = `%${clampDiscount(product.discountPercent)}`;\n imgWrapper.appendChild(badge);\n }\n\n card.appendChild(imgWrapper);\n\n // Info section\n const info = document.createElement('div');\n info.className = 'gengage-simrel-card-info gengage-chat-product-card-body';\n\n // Brand\n if (product.brand) {\n const brandEl = document.createElement('div');\n brandEl.className = 'gengage-simrel-card-brand gengage-chat-product-card-brand';\n brandEl.textContent = product.brand;\n info.appendChild(brandEl);\n }\n\n // Name\n const nameEl = document.createElement('div');\n nameEl.className = 'gengage-simrel-card-name gengage-chat-product-card-name';\n nameEl.textContent = product.name;\n info.appendChild(nameEl);\n\n // Rating\n if (product.rating != null && product.rating > 0) {\n const ratingEl = document.createElement('div');\n ratingEl.className = 'gengage-simrel-card-rating gengage-chat-product-card-rating';\n ratingEl.appendChild(createStarRatingElement(product.rating));\n if (product.reviewCount != null) {\n const count = document.createElement('span');\n count.className = 'gengage-simrel-card-review-count gengage-chat-product-card-review-count';\n count.textContent = ` (${product.reviewCount})`;\n ratingEl.appendChild(count);\n }\n info.appendChild(ratingEl);\n }\n\n // Price\n const priceContainer = document.createElement('div');\n priceContainer.className = 'gengage-simrel-card-price gengage-chat-product-card-price';\n\n if (product.originalPrice && product.originalPrice !== product.price) {\n if (discountType === 'strike-through' || !discountType) {\n const original = document.createElement('span');\n original.className = 'gengage-simrel-card-price-original gengage-chat-product-card-original-price';\n original.textContent = formatPrice(product.originalPrice, pricing);\n priceContainer.appendChild(original);\n }\n }\n\n if (product.price) {\n const current = document.createElement('span');\n current.className = 'gengage-simrel-card-price-current gengage-chat-product-card-price-current';\n current.textContent = formatPrice(product.price, pricing);\n priceContainer.appendChild(current);\n }\n\n info.appendChild(priceContainer);\n card.appendChild(info);\n\n // Keep SimRel cards aligned with chat product-card structure.\n const cta = document.createElement('button');\n cta.className = 'gengage-simrel-card-cta gengage-chat-product-card-cta';\n cta.type = 'button';\n cta.textContent = i18n?.ctaLabel ?? 'View';\n cta.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n onClick(product);\n });\n card.appendChild(cta);\n\n // Add to cart stepper or out-of-stock indicator\n if (product.inStock === false) {\n const oos = document.createElement('div');\n oos.className = 'gengage-simrel-card-oos';\n oos.textContent = i18n?.outOfStockLabel ?? 'Out of Stock';\n card.appendChild(oos);\n } else if (product.cartCode) {\n const cartCode = product.cartCode;\n const stepper = createQuantityStepper({\n compact: true,\n label: i18n?.addToCartButton ?? 'Add to Cart',\n onSubmit: (quantity) => {\n onAddToCart({ sku: product.sku, quantity, cartCode });\n },\n });\n stepper.classList.add('gengage-simrel-atc');\n card.appendChild(stepper);\n }\n\n // Card click → navigate\n card.addEventListener('click', (e) => {\n if ((e.target as HTMLElement).closest('.gengage-simrel-atc')) return;\n if ((e.target as HTMLElement).closest('.gengage-chat-product-card-atc')) return;\n if ((e.target as HTMLElement).closest('.gengage-chat-product-card-cta')) return;\n onClick(product);\n });\n\n return card;\n}\n","import type { NormalizedProduct } from '../../common/protocol-adapter.js';\nimport type { SimRelI18n } from '../types.js';\nimport { renderProductCard } from './ProductCard.js';\nimport type { ProductCardOptions } from './ProductCard.js';\n\nexport interface ProductGridOptions {\n products: NormalizedProduct[];\n columns?: number;\n discountType?: 'strike-through' | 'badge';\n onClick: (product: NormalizedProduct) => void;\n onAddToCart: (params: { sku: string; quantity: number; cartCode: string }) => void;\n renderCard?: (product: NormalizedProduct, index: number) => string;\n renderCardElement?: (product: NormalizedProduct, index: number) => HTMLElement | null;\n i18n?: SimRelI18n;\n}\n\nexport function renderProductGrid(options: ProductGridOptions): HTMLElement {\n const grid = document.createElement('div');\n grid.className = 'gengage-simrel-grid';\n grid.setAttribute('role', 'list');\n grid.setAttribute('aria-label', options.i18n?.similarProductsAriaLabel ?? 'Similar products');\n\n if (options.columns) {\n grid.style.setProperty('--gengage-simrel-columns', String(options.columns));\n }\n\n for (let i = 0; i < options.products.length; i++) {\n const product = options.products[i]!;\n const cardOpts: ProductCardOptions = {\n product,\n index: i,\n onClick: options.onClick,\n onAddToCart: options.onAddToCart,\n };\n if (options.i18n !== undefined) cardOpts.i18n = options.i18n;\n if (options.discountType !== undefined) cardOpts.discountType = options.discountType;\n if (options.renderCard !== undefined) cardOpts.renderCard = options.renderCard;\n if (options.renderCardElement !== undefined) cardOpts.renderCardElement = options.renderCardElement;\n const card = renderProductCard(cardOpts);\n grid.appendChild(card);\n }\n\n if (options.products.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'gengage-simrel-empty';\n empty.textContent = options.i18n?.emptyStateMessage ?? 'No similar products found.';\n grid.appendChild(empty);\n }\n\n return grid;\n}\n","import type { NormalizedProduct } from '../../common/protocol-adapter.js';\nimport type { ProductGroup } from '../api.js';\nimport type { SimRelI18n } from '../types.js';\nimport { renderProductGrid } from './ProductGrid.js';\n\nexport interface GroupTabsOptions {\n groups: ProductGroup[];\n discountType?: 'strike-through' | 'badge';\n onClick: (product: NormalizedProduct) => void;\n onAddToCart: (params: { sku: string; quantity: number; cartCode: string }) => void;\n renderCard?: (product: NormalizedProduct, index: number) => string;\n renderCardElement?: (product: NormalizedProduct, index: number) => HTMLElement | null;\n i18n?: SimRelI18n;\n}\n\nlet _groupTabsInstanceCounter = 0;\n\nexport function renderGroupTabs(options: GroupTabsOptions): HTMLElement {\n const instanceId = _groupTabsInstanceCounter++;\n const container = document.createElement('div');\n container.className = 'gengage-simrel-groups';\n\n if (options.groups.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'gengage-simrel-empty';\n empty.textContent = options.i18n?.emptyStateMessage ?? 'No similar products found.';\n container.appendChild(empty);\n return container;\n }\n\n // Tab bar — WAI-ARIA tablist pattern\n const tabBar = document.createElement('div');\n tabBar.className = 'gengage-simrel-tabs';\n tabBar.setAttribute('role', 'tablist');\n\n const tabs: HTMLButtonElement[] = [];\n const panels: HTMLElement[] = [];\n\n const buildGridOptions = (group: ProductGroup): import('./ProductGrid.js').ProductGridOptions => {\n const gridOpts: import('./ProductGrid.js').ProductGridOptions = {\n products: group.products,\n onClick: options.onClick,\n onAddToCart: options.onAddToCart,\n };\n if (options.i18n !== undefined) gridOpts.i18n = options.i18n;\n if (options.discountType !== undefined) gridOpts.discountType = options.discountType;\n if (options.renderCard !== undefined) gridOpts.renderCard = options.renderCard;\n if (options.renderCardElement !== undefined) gridOpts.renderCardElement = options.renderCardElement;\n return gridOpts;\n };\n\n const activateTab = (index: number): void => {\n for (let j = 0; j < tabs.length; j++) {\n const isActive = j === index;\n tabs[j]!.classList.toggle('gengage-simrel-tab--active', isActive);\n tabs[j]!.setAttribute('aria-selected', String(isActive));\n tabs[j]!.tabIndex = isActive ? 0 : -1;\n }\n\n // Lazy-render the grid content for the active panel\n const group = options.groups[index]!;\n const panel = panels[index]!;\n panel.innerHTML = '';\n const grid = renderProductGrid(buildGridOptions(group));\n panel.appendChild(grid);\n\n // Show only the active panel and manage tabindex for keyboard access\n for (let j = 0; j < panels.length; j++) {\n const isActive = j === index;\n panels[j]!.style.display = isActive ? '' : 'none';\n panels[j]!.tabIndex = isActive ? 0 : -1;\n }\n };\n\n for (let i = 0; i < options.groups.length; i++) {\n const group = options.groups[i]!;\n const tabId = `gengage-simrel-tab-${instanceId}-${i}`;\n const panelId = `gengage-simrel-panel-${instanceId}-${i}`;\n\n // Tab button\n const tab = document.createElement('button');\n tab.className = 'gengage-simrel-tab';\n tab.type = 'button';\n tab.id = tabId;\n tab.textContent = group.name;\n tab.setAttribute('role', 'tab');\n tab.setAttribute('aria-controls', panelId);\n tab.setAttribute('aria-selected', String(i === 0));\n tab.tabIndex = i === 0 ? 0 : -1;\n if (i === 0) tab.classList.add('gengage-simrel-tab--active');\n\n tab.addEventListener('click', () => activateTab(i));\n tab.addEventListener('keydown', (e: KeyboardEvent) => {\n let next = -1;\n if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {\n next = (i + 1) % options.groups.length;\n } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {\n next = (i - 1 + options.groups.length) % options.groups.length;\n } else if (e.key === 'Home') {\n next = 0;\n } else if (e.key === 'End') {\n next = options.groups.length - 1;\n }\n if (next >= 0) {\n e.preventDefault();\n activateTab(next);\n tabs[next]!.focus();\n }\n });\n\n tabs.push(tab);\n tabBar.appendChild(tab);\n\n // Tab panel\n const panel = document.createElement('div');\n panel.className = 'gengage-simrel-tab-panel';\n panel.id = panelId;\n panel.setAttribute('role', 'tabpanel');\n panel.setAttribute('aria-labelledby', tabId);\n panel.tabIndex = i === 0 ? 0 : -1;\n if (i !== 0) panel.style.display = 'none';\n\n panels.push(panel);\n }\n\n container.appendChild(tabBar);\n\n // Render the initial (first) tab content\n const firstPanel = panels[0]!;\n const firstGrid = renderProductGrid(buildGridOptions(options.groups[0]!));\n firstPanel.appendChild(firstGrid);\n\n for (const panel of panels) container.appendChild(panel);\n\n return container;\n}\n","import { renderUISpecWithRegistry } from '../../common/renderer/index.js';\nimport type { UISpecDomRegistry, UISpecDomUnknownRenderer } from '../../common/renderer/index.js';\nimport type { UISpec, ActionPayload } from '../../common/types.js';\nimport type { SimRelUISpecRenderContext, SimilarProduct } from '../types.js';\nimport type { ProductGroup } from '../api.js';\nimport { renderProductCard } from './ProductCard.js';\nimport { renderGroupTabs } from './GroupTabs.js';\n\nexport type SimRelUISpecRegistry = UISpecDomRegistry<SimRelUISpecRenderContext>;\n\nfunction toSimRelProduct(raw: unknown): SimilarProduct | null {\n if (!raw || typeof raw !== 'object') return null;\n const obj = raw as Record<string, unknown>;\n if (typeof obj['sku'] !== 'string' || typeof obj['name'] !== 'string' || typeof obj['url'] !== 'string') {\n return null;\n }\n\n const result: SimilarProduct = {\n sku: obj['sku'],\n name: obj['name'],\n url: obj['url'],\n };\n\n const imageUrl = obj['imageUrl'];\n if (typeof imageUrl === 'string') result.imageUrl = imageUrl;\n const price = obj['price'];\n if (typeof price === 'string') result.price = price;\n const originalPrice = obj['originalPrice'];\n if (typeof originalPrice === 'string') result.originalPrice = originalPrice;\n const discountPercent = obj['discountPercent'];\n if (typeof discountPercent === 'number') result.discountPercent = discountPercent;\n const brand = obj['brand'];\n if (typeof brand === 'string') result.brand = brand;\n const rating = obj['rating'];\n if (typeof rating === 'number') result.rating = rating;\n const reviewCount = obj['reviewCount'];\n if (typeof reviewCount === 'number') result.reviewCount = reviewCount;\n const cartCode = obj['cartCode'];\n if (typeof cartCode === 'string') result.cartCode = cartCode;\n const inStock = obj['inStock'];\n if (typeof inStock === 'boolean') result.inStock = inStock;\n const extras = obj['extras'];\n if (extras != null && typeof extras === 'object') result.extras = extras as Record<string, unknown>;\n\n return result;\n}\n\nfunction toActionPayload(raw: unknown): ActionPayload | null {\n if (!raw || typeof raw !== 'object') return null;\n const obj = raw as Record<string, unknown>;\n const title = obj['title'];\n const type = obj['type'];\n if (typeof title !== 'string' || typeof type !== 'string') return null;\n const action: ActionPayload = { title, type };\n if (obj['payload'] !== undefined) action.payload = obj['payload'];\n return action;\n}\n\nconst DEFAULT_SIMREL_UI_SPEC_REGISTRY: SimRelUISpecRegistry = {\n ProductGrid: ({ element, renderElement, context }) => {\n const grid = document.createElement('div');\n grid.className = 'gengage-simrel-grid';\n grid.setAttribute('role', 'list');\n\n const columns = element.props?.['columns'];\n if (typeof columns === 'number' && Number.isFinite(columns) && columns > 0) {\n grid.style.setProperty('--gengage-simrel-columns', String(columns));\n }\n\n for (const childId of element.children ?? []) {\n const rendered = renderElement(childId);\n if (rendered) grid.appendChild(rendered);\n }\n\n if (grid.children.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'gengage-simrel-empty';\n empty.textContent = context.i18n.emptyStateMessage;\n grid.appendChild(empty);\n }\n\n return grid;\n },\n\n ProductCard: ({ element, context }) => {\n const productRaw = (element.props?.['product'] ?? element.props) as unknown;\n const product = toSimRelProduct(productRaw);\n if (!product) return null;\n\n const indexRaw = element.props?.['index'];\n const index = typeof indexRaw === 'number' && Number.isFinite(indexRaw) ? indexRaw : 0;\n const discountTypeRaw = element.props?.['discountType'];\n const discountType =\n discountTypeRaw === 'strike-through' || discountTypeRaw === 'badge' ? discountTypeRaw : context.discountType;\n\n const options: import('./ProductCard.js').ProductCardOptions = {\n product,\n index,\n onClick: context.onClick,\n onAddToCart: context.onAddToCart,\n i18n: context.i18n,\n };\n if (discountType !== undefined) options.discountType = discountType;\n if (context.renderCard !== undefined) options.renderCard = context.renderCard;\n if (context.renderCardElement !== undefined) options.renderCardElement = context.renderCardElement;\n if (context.pricing !== undefined) options.pricing = context.pricing;\n return renderProductCard(options);\n },\n\n GroupTabs: ({ element, context }) => {\n const groupsRaw = element.props?.['groups'];\n if (!Array.isArray(groupsRaw)) return null;\n const groups: ProductGroup[] = [];\n\n for (const entry of groupsRaw) {\n if (!entry || typeof entry !== 'object') continue;\n const obj = entry as Record<string, unknown>;\n if (typeof obj['name'] !== 'string') continue;\n\n const products: SimilarProduct[] = [];\n if (Array.isArray(obj['products'])) {\n for (const rawProduct of obj['products']) {\n const normalized = toSimRelProduct(rawProduct);\n if (normalized) products.push(normalized);\n }\n }\n\n const group: ProductGroup = {\n name: obj['name'],\n products,\n };\n if (typeof obj['highlight'] === 'string') group.highlight = obj['highlight'];\n groups.push(group);\n }\n\n const options: import('./GroupTabs.js').GroupTabsOptions = {\n groups,\n onClick: context.onClick,\n onAddToCart: context.onAddToCart,\n i18n: context.i18n,\n };\n if (context.discountType !== undefined) options.discountType = context.discountType;\n if (context.renderCard !== undefined) options.renderCard = context.renderCard;\n if (context.renderCardElement !== undefined) options.renderCardElement = context.renderCardElement;\n return renderGroupTabs(options);\n },\n\n EmptyState: ({ element, context }) => {\n const empty = document.createElement('div');\n empty.className = 'gengage-simrel-empty';\n const message = element.props?.['message'];\n empty.textContent = typeof message === 'string' ? message : context.i18n.emptyStateMessage;\n return empty;\n },\n\n AddToCartButton: ({ element, context }) => {\n const sku = element.props?.['sku'];\n const cartCode = element.props?.['cartCode'];\n if (typeof sku !== 'string' || typeof cartCode !== 'string') return null;\n\n const button = document.createElement('button');\n button.className = 'gengage-simrel-atc gengage-chat-product-card-cta';\n button.type = 'button';\n const label = element.props?.['label'];\n button.textContent = typeof label === 'string' ? label : context.i18n.addToCartButton;\n button.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n context.onAddToCart({ sku, quantity: 1, cartCode });\n });\n return button;\n },\n\n QuickActions: ({ element, context }) => {\n const wrapper = document.createElement('div');\n wrapper.className = 'gengage-simrel-quick-actions';\n const actions = element.props?.['actions'];\n if (!Array.isArray(actions) || !context.onAction) return wrapper;\n\n for (const raw of actions) {\n if (!raw || typeof raw !== 'object') continue;\n const actionObj = raw as Record<string, unknown>;\n const label = actionObj['label'];\n const action = toActionPayload(actionObj['action']);\n if (typeof label !== 'string' || !action) continue;\n\n const button = document.createElement('button');\n button.className = 'gengage-simrel-quick-action';\n button.type = 'button';\n button.textContent = label;\n button.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n context.onAction?.(action);\n });\n wrapper.appendChild(button);\n }\n return wrapper;\n },\n};\n\nexport const defaultSimRelUnknownUISpecRenderer: UISpecDomUnknownRenderer<SimRelUISpecRenderContext> = ({\n element,\n renderElement,\n}) => {\n if (import.meta.env?.DEV) {\n console.warn(`[gengage:simrel] Unknown ui_spec component type: ${element.type}`);\n }\n if (!element.children || element.children.length === 0) {\n return null;\n }\n const wrapper = document.createElement('div');\n for (const childId of element.children) {\n const rendered = renderElement(childId);\n if (rendered) wrapper.appendChild(rendered);\n }\n return wrapper;\n};\n\nexport function createDefaultSimRelUISpecRegistry(): SimRelUISpecRegistry {\n return { ...DEFAULT_SIMREL_UI_SPEC_REGISTRY };\n}\n\nexport function renderSimRelUISpec(\n spec: UISpec,\n context: SimRelUISpecRenderContext,\n registry = DEFAULT_SIMREL_UI_SPEC_REGISTRY,\n unknownRenderer: UISpecDomUnknownRenderer<SimRelUISpecRenderContext> = defaultSimRelUnknownUISpecRenderer,\n): HTMLElement {\n return renderUISpecWithRegistry({\n spec,\n context,\n registry,\n containerClassName: 'gengage-simrel-uispec',\n unknownRenderer,\n });\n}\n","import type { SimRelI18n } from '../types.js';\n\nexport const SIMREL_I18N_TR: SimRelI18n = {\n similarProductsAriaLabel: 'Benzer ürünler',\n emptyStateMessage: 'Benzer ürün bulunamadı.',\n addToCartButton: 'Sepete Ekle',\n ctaLabel: 'İncele',\n outOfStockLabel: 'Stokta Yok',\n priceSuffix: ' TL',\n};\n","import type { SimRelI18n } from '../types.js';\n\nexport const SIMREL_I18N_EN: SimRelI18n = {\n similarProductsAriaLabel: 'Similar products',\n emptyStateMessage: 'No similar products found.',\n addToCartButton: 'Add to cart',\n ctaLabel: 'View',\n outOfStockLabel: 'Out of Stock',\n priceSuffix: '',\n};\n","import type { SimRelI18n } from '../types.js';\nimport { SIMREL_I18N_TR } from './tr.js';\nimport { SIMREL_I18N_EN } from './en.js';\n\nfunction normalizeLocale(locale?: string): string {\n if (!locale) return 'tr';\n return locale.toLowerCase().split('-')[0] ?? 'tr';\n}\n\nexport function resolveSimRelLocale(locale?: string): SimRelI18n {\n switch (normalizeLocale(locale)) {\n case 'en':\n return SIMREL_I18N_EN;\n default:\n return SIMREL_I18N_TR;\n }\n}\n\nexport { SIMREL_I18N_TR, SIMREL_I18N_EN };\n","/**\n * Similar Products (SimRel) widget — json-render catalog definition.\n *\n * Backend endpoints:\n * POST /chat/similar_products — primary product list\n * POST /chat/product_groupings — grouped/tabbed view\n *\n * The backend streams NDJSON events. `ui_spec` events reference\n * component names defined below. Implementations live in ./registry.\n */\n\nimport { z } from 'zod';\n\nconst SimilarProductSchema = z.object({\n sku: z.string(),\n name: z.string(),\n imageUrl: z.string().url().optional(),\n price: z.string().optional(),\n originalPrice: z.string().optional(),\n discountPercent: z.number().optional(),\n url: z.string().url(),\n brand: z.string().optional(),\n rating: z.number().min(0).max(5).optional(),\n reviewCount: z.number().int().nonnegative().optional(),\n});\n\nexport const ProductGridSchema = z.object({\n layout: z.enum(['grid', 'carousel']).optional(),\n columns: z.number().int().positive().optional(),\n});\n\nexport const ProductCardSchema = z.object({\n product: SimilarProductSchema,\n index: z.number().int().nonnegative(),\n discountType: z.enum(['strike-through', 'badge']).optional(),\n});\n\nexport const AddToCartButtonSchema = z.object({\n sku: z.string(),\n label: z.string().optional(),\n cartCode: z.string(),\n});\n\nexport const QuickActionsSchema = z.object({\n actions: z.array(\n z.object({\n label: z.string(),\n action: z.object({\n title: z.string(),\n type: z.string(),\n payload: z.unknown().optional(),\n }),\n }),\n ),\n});\n\nexport const EmptyStateSchema = z.object({\n message: z.string().optional(),\n});\n\nexport const simRelCatalog = {\n components: {\n ProductGrid: {\n schema: ProductGridSchema,\n description: 'Outer grid or carousel container for similar products.',\n },\n ProductCard: {\n schema: ProductCardSchema,\n description: 'A single product card with image, title, price, and actions.',\n },\n AddToCartButton: {\n schema: AddToCartButtonSchema,\n description: 'Add-to-cart CTA rendered inside or below a product card.',\n },\n QuickActions: {\n schema: QuickActionsSchema,\n description: 'A row of quick-action buttons below product info.',\n },\n EmptyState: {\n schema: EmptyStateSchema,\n description: 'Empty state shown when no similar products are available.',\n },\n },\n} as const;\n\nexport type SimRelCatalog = typeof simRelCatalog;\nexport type SimRelComponentName = keyof SimRelCatalog['components'];\n","/**\n * Similar Products (SimRel) widget — public entry point.\n *\n * Fetches and renders similar / related products for the current SKU.\n * Backend: POST /chat/similar_products + /chat/product_groupings\n */\n\nimport type { PageContext, UISpec, UIElement } from '../common/types.js';\nimport type { NormalizedProduct } from '../common/protocol-adapter.js';\nimport type { ChatTransportConfig } from '../common/api-paths.js';\nimport type { UISpecRenderHelpers } from '../common/renderer/index.js';\nimport { mergeUISpecRegistry } from '../common/renderer/index.js';\nimport { BaseWidget } from '../common/widget-base.js';\nimport { dispatch } from '../common/events.js';\nimport { getGlobalErrorMessage } from '../common/global-error-toast.js';\nimport {\n streamStartEvent,\n streamDoneEvent,\n streamErrorEvent,\n basketAddEvent,\n widgetHistorySnapshotEvent,\n} from '../common/analytics-events.js';\nimport { fetchSimilarProducts, fetchProductGroupings } from './api.js';\nimport {\n createDefaultSimRelUISpecRegistry,\n defaultSimRelUnknownUISpecRenderer,\n renderSimRelUISpec,\n} from './components/renderUISpec.js';\nimport type { SimRelWidgetConfig, SimilarProduct, SimRelI18n, SimRelUISpecRenderContext } from './types.js';\nimport { SIMREL_I18N_TR, resolveSimRelLocale } from './locales/index.js';\nimport * as ga from '../common/ga-datalayer.js';\n\nimport './components/simrel.css';\n\n/**\n * Similar / related products widget for product pages.\n * Fetches AI-powered product recommendations and renders them as a scrollable grid.\n *\n * @example\n * ```ts\n * import { GengageSimRel, bootstrapSession } from '@gengage/assistant-fe';\n *\n * const simrel = new GengageSimRel();\n * await simrel.init({\n * accountId: 'mystore',\n * middlewareUrl: 'https://chat.gengage.ai',\n * sku: '12345',\n * mountTarget: '#similar-products',\n * session: { sessionId: bootstrapSession() },\n * onAddToCart: ({ sku, quantity }) => cart.add(sku, quantity),\n * });\n * ```\n */\nexport class GengageSimRel extends BaseWidget<SimRelWidgetConfig> {\n private _abortController: AbortController | null = null;\n private _contentEl: HTMLElement | null = null;\n private _lastSku: string | undefined;\n private _i18n: SimRelI18n = SIMREL_I18N_TR;\n\n protected async onInit(config: SimRelWidgetConfig): Promise<void> {\n this._i18n = this._resolveI18n(config);\n\n this._contentEl = document.createElement('div');\n this._contentEl.className = 'gengage-simrel-container';\n this.root.appendChild(this._contentEl);\n\n this._lastSku = config.sku;\n await this._fetchAndRender(config.sku);\n this.isVisible = true;\n ga.trackInit('simrel');\n }\n\n protected onUpdate(context: Partial<PageContext>): void {\n const newSku = context.sku;\n if (!newSku || newSku === this._lastSku) return;\n this._lastSku = newSku;\n void this._fetchAndRender(newSku);\n }\n\n protected onShow(): void {\n if (this._contentEl) {\n this._contentEl.style.opacity = '0';\n this._contentEl.style.transition = 'opacity 0.3s ease-in';\n requestAnimationFrame(() => {\n if (this._contentEl) this._contentEl.style.opacity = '1';\n });\n }\n }\n\n protected onHide(): void {\n // Preserve fetched products for re-show\n }\n\n protected onDestroy(): void {\n this._abort();\n if (this._contentEl) {\n this._contentEl.remove();\n this._contentEl = null;\n }\n }\n\n // ---------------------------------------------------------------------------\n // Internal event dispatchers\n // ---------------------------------------------------------------------------\n\n _handleProductClick(product: NormalizedProduct): void {\n const simRelProduct: SimilarProduct = {\n sku: product.sku,\n name: product.name,\n url: product.url,\n };\n if (product.imageUrl !== undefined) simRelProduct.imageUrl = product.imageUrl;\n if (product.price !== undefined) simRelProduct.price = product.price;\n if (product.originalPrice !== undefined) simRelProduct.originalPrice = product.originalPrice;\n if (product.discountPercent !== undefined) simRelProduct.discountPercent = product.discountPercent;\n if (product.brand !== undefined) simRelProduct.brand = product.brand;\n if (product.rating !== undefined) simRelProduct.rating = product.rating;\n if (product.reviewCount !== undefined) simRelProduct.reviewCount = product.reviewCount;\n if (product.cartCode !== undefined) simRelProduct.cartCode = product.cartCode;\n if (product.inStock !== undefined) simRelProduct.inStock = product.inStock;\n\n if (this.config.onProductClick?.(simRelProduct) === false) return;\n\n ga.trackProductDetail(product.sku, product.name);\n const sessionId = this.config.session?.sessionId ?? null;\n dispatch('gengage:similar:product-click', {\n sku: product.sku,\n url: product.url,\n sessionId,\n });\n\n this.config.onProductNavigate?.(product.url, product.sku, sessionId);\n }\n\n _handleAddToCart(params: { sku: string; quantity: number; cartCode: string }): void {\n ga.trackCartAdd(params.sku, params.quantity);\n this.config.onAddToCart?.(params);\n dispatch('gengage:similar:add-to-cart', params);\n\n this.track(\n basketAddEvent(this.analyticsContext(), {\n attribution_source: 'simrel',\n attribution_action_id: crypto.randomUUID(),\n cart_value: 0, // Host page should enrich via event listener\n currency: 'TRY',\n line_items: params.quantity,\n sku: params.sku,\n }),\n );\n }\n\n // ---------------------------------------------------------------------------\n // Private\n // ---------------------------------------------------------------------------\n\n private _abort(): void {\n this._abortController?.abort();\n this._abortController = null;\n }\n\n private async _fetchAndRender(sku: string): Promise<void> {\n this._abort();\n this._abortController = new AbortController();\n // Capture signal reference at invocation time to avoid race conditions:\n // if onUpdate fires between awaits, `this._abortController` gets swapped\n // but `signal` still refers to this invocation's controller.\n const signal = this._abortController.signal;\n\n if (!this._contentEl) return;\n this._contentEl.innerHTML = '';\n // Reset visibility in case a previous error set display:none\n this._contentEl.style.display = '';\n\n // Show loading spinner\n const loading = document.createElement('div');\n loading.className = 'gengage-simrel-loading';\n const spinner = document.createElement('div');\n spinner.className = 'gengage-simrel-spinner';\n loading.appendChild(spinner);\n this._contentEl.appendChild(loading);\n\n const transport: ChatTransportConfig = {\n middlewareUrl: this.config.middlewareUrl,\n };\n\n const requestId = crypto.randomUUID();\n const fetchStart = Date.now();\n\n this.track(\n streamStartEvent(this.analyticsContext(), {\n endpoint: 'similar_products',\n request_id: requestId,\n widget: 'simrel',\n }),\n );\n\n try {\n // Fetch similar products\n const simReq: import('./api.js').SimilarProductsRequest = {\n account_id: this.config.accountId,\n session_id: this.config.session?.sessionId ?? '',\n correlation_id: this.config.session?.sessionId ?? '',\n sku,\n };\n if (this.config.domain !== undefined) simReq.domain = this.config.domain;\n const products = await fetchSimilarProducts(simReq, transport, signal);\n\n if (!this._contentEl) return;\n this._contentEl.innerHTML = '';\n\n // Try to fetch product groupings for tabbed view\n if (products.length > 0) {\n try {\n const skus = products.map((p) => p.sku);\n const groups = await fetchProductGroupings(\n {\n account_id: this.config.accountId,\n session_id: this.config.session?.sessionId ?? '',\n correlation_id: this.config.session?.sessionId ?? '',\n skus,\n },\n transport,\n signal,\n );\n\n if (groups.length > 0 && this._contentEl) {\n const groupsSpec = this._buildGroupsSpec(groups);\n const renderedGroups = this._renderUISpec(groupsSpec);\n this._contentEl.appendChild(renderedGroups);\n\n ga.trackShow('simrel');\n this.track(\n streamDoneEvent(this.analyticsContext(), {\n request_id: requestId,\n latency_ms: Date.now() - fetchStart,\n chunk_count: groups.reduce((n, g) => n + g.products.length, 0),\n widget: 'simrel',\n }),\n );\n this.track(\n widgetHistorySnapshotEvent(this.analyticsContext(), {\n message_count: groups.reduce((n, g) => n + g.products.length, 0),\n history_ref: requestId,\n redaction_level: 'none',\n widget: 'simrel',\n }),\n );\n return;\n }\n } catch {\n // Product groupings is optional; fall through to flat grid\n }\n }\n\n // Flat grid (no groupings or groupings failed)\n if (this._contentEl) {\n const gridSpec = this._buildProductsSpec(products);\n const renderedGrid = this._renderUISpec(gridSpec);\n this._contentEl.appendChild(renderedGrid);\n }\n\n if (products.length > 0) {\n ga.trackShow('simrel');\n }\n\n this.track(\n streamDoneEvent(this.analyticsContext(), {\n request_id: requestId,\n latency_ms: Date.now() - fetchStart,\n chunk_count: products.length,\n widget: 'simrel',\n }),\n );\n\n this.track(\n widgetHistorySnapshotEvent(this.analyticsContext(), {\n message_count: products.length,\n history_ref: requestId,\n redaction_level: 'none',\n widget: 'simrel',\n }),\n );\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') return;\n\n dispatch('gengage:global:error', {\n source: 'simrel',\n code: 'FETCH_ERROR',\n message: getGlobalErrorMessage(this.config.locale),\n });\n\n this.track(\n streamErrorEvent(this.analyticsContext(), {\n request_id: requestId,\n error_code: 'FETCH_ERROR',\n error_message: err instanceof Error ? err.message : String(err),\n widget: 'simrel',\n }),\n );\n\n if (import.meta.env?.DEV) {\n console.error('[gengage:simrel] Failed to fetch similar products:', err);\n }\n // Show inline error with retry instead of hiding silently\n if (this._contentEl) {\n this._contentEl.innerHTML = '';\n const errorEl = document.createElement('div');\n errorEl.className = 'gengage-simrel-error';\n errorEl.style.cssText = 'text-align:center;padding:16px;color:#6b7280;font-size:13px;';\n const msgEl = document.createElement('span');\n msgEl.textContent = this.config.locale?.startsWith('tr')\n ? 'Benzer \\u00FCr\\u00FCnler y\\u00FCklenemedi.'\n : 'Could not load similar products.';\n errorEl.appendChild(msgEl);\n const retryBtn = document.createElement('button');\n retryBtn.textContent = this.config.locale?.startsWith('tr') ? 'Tekrar dene' : 'Try again';\n retryBtn.style.cssText =\n 'margin-left:8px;border:1px solid #d1d5db;background:#fff;border-radius:6px;padding:4px 12px;cursor:pointer;font-size:13px;color:#374151;';\n retryBtn.addEventListener('click', () => {\n void this._fetchAndRender(this.config.sku);\n });\n errorEl.appendChild(retryBtn);\n this._contentEl.appendChild(errorEl);\n }\n }\n }\n\n private _resolveI18n(config: SimRelWidgetConfig): SimRelI18n {\n const base = resolveSimRelLocale(config.locale);\n return { ...base, ...config.i18n };\n }\n\n private _resolveUISpecRegistry() {\n const baseRegistry = createDefaultSimRelUISpecRegistry();\n return mergeUISpecRegistry(baseRegistry, this.config.renderer?.registry);\n }\n\n private _buildRenderContext(): SimRelUISpecRenderContext {\n const renderCard = this.config.renderCard as ((product: SimilarProduct, index: number) => string) | undefined;\n const context: SimRelUISpecRenderContext = {\n onClick: (product) => this._handleProductClick(product as unknown as NormalizedProduct),\n onAddToCart: (params) => this._handleAddToCart(params),\n i18n: this._i18n,\n };\n if (this.config.discountType !== undefined) context.discountType = this.config.discountType;\n if (renderCard !== undefined) context.renderCard = renderCard;\n if (this.config.renderCardElement !== undefined) {\n context.renderCardElement = this.config.renderCardElement as (\n product: SimilarProduct,\n index: number,\n ) => HTMLElement | null;\n }\n if (this.config.pricing !== undefined) context.pricing = this.config.pricing;\n return context;\n }\n\n private _renderUISpec(spec: UISpec): HTMLElement {\n const registry = this._resolveUISpecRegistry();\n const context = this._buildRenderContext();\n const unknownRenderer = this.config.renderer?.unknownRenderer ?? defaultSimRelUnknownUISpecRenderer;\n const defaultRender = (inputSpec: UISpec, inputContext: SimRelUISpecRenderContext) =>\n renderSimRelUISpec(inputSpec, inputContext, registry, unknownRenderer);\n\n const override = this.config.renderer?.renderUISpec;\n if (!override) return defaultRender(spec, context);\n\n const helpers: UISpecRenderHelpers<SimRelUISpecRenderContext> = {\n registry,\n unknownRenderer,\n defaultRender,\n };\n return override(spec, context, helpers);\n }\n\n private _buildProductsSpec(products: NormalizedProduct[]): UISpec {\n const elements: Record<string, UIElement> = {};\n const children: string[] = [];\n for (let i = 0; i < products.length; i++) {\n const product = products[i]!;\n const id = `product-${i}`;\n children.push(id);\n elements[id] = {\n type: 'ProductCard',\n props: {\n product,\n index: i,\n discountType: this.config.discountType,\n },\n };\n }\n elements['root'] = {\n type: 'ProductGrid',\n props: {\n layout: 'grid',\n },\n children,\n };\n return {\n root: 'root',\n elements,\n };\n }\n\n private _buildGroupsSpec(\n groups: Array<{\n name: string;\n highlight?: string;\n products: NormalizedProduct[];\n }>,\n ): UISpec {\n return {\n root: 'root',\n elements: {\n root: {\n type: 'GroupTabs',\n props: { groups },\n },\n },\n };\n }\n}\n\nexport function createSimRelWidget(): GengageSimRel {\n return new GengageSimRel();\n}\n\nexport type {\n SimRelWidgetConfig,\n SimilarProduct,\n SimRelUIComponents,\n SimRelI18n,\n SimRelUISpecRenderContext,\n SimRelRendererConfig,\n} from './types.js';\nexport {\n renderSimRelUISpec,\n createDefaultSimRelUISpecRegistry,\n defaultSimRelUnknownUISpecRenderer,\n} from './components/renderUISpec.js';\nexport type { SimRelUISpecRegistry } from './components/renderUISpec.js';\nexport { simRelCatalog } from './catalog.js';\nexport type { SimRelCatalog, SimRelComponentName } from './catalog.js';\n"],"names":["extractProductCardsFromSpec","elements","products","el","product","isNDJSONResponse","response","ct","collectProductsFromStream","signal","opts","event","normalized","adaptBackendEvent","consumeStream","fetchSimilarProducts","request","transport","url","buildChatEndpointUrl","fetchInit","text","normalizeSimilarProductsResponse","collectGroupingsFromStream","groups","currentGroup","name","highlight","fetchProductGroupings","normalizeProductGroupingsResponse","renderProductCard","options","index","discountType","onClick","onAddToCart","renderCard","i18n","pricing","wrapper","sanitizeHtml","e","card","imgWrapper","isSafeImageUrl","img","addImageErrorHandler","badge","clampDiscount","info","brandEl","nameEl","ratingEl","createStarRatingElement","count","priceContainer","original","formatPrice","current","cta","oos","cartCode","stepper","createQuantityStepper","quantity","renderProductGrid","grid","i","cardOpts","empty","_groupTabsInstanceCounter","renderGroupTabs","instanceId","container","tabBar","tabs","panels","buildGridOptions","group","gridOpts","activateTab","j","isActive","panel","tabId","panelId","tab","next","firstPanel","firstGrid","toSimRelProduct","raw","obj","result","imageUrl","price","originalPrice","discountPercent","brand","rating","reviewCount","inStock","extras","toActionPayload","title","type","action","DEFAULT_SIMREL_UI_SPEC_REGISTRY","element","renderElement","context","columns","childId","rendered","productRaw","indexRaw","discountTypeRaw","groupsRaw","entry","rawProduct","message","sku","button","label","actions","actionObj","defaultSimRelUnknownUISpecRenderer","createDefaultSimRelUISpecRegistry","renderSimRelUISpec","spec","registry","unknownRenderer","renderUISpecWithRegistry","SIMREL_I18N_TR","SIMREL_I18N_EN","normalizeLocale","locale","resolveSimRelLocale","SimilarProductSchema","z.object","z.string","z.number","ProductGridSchema","z.enum","ProductCardSchema","AddToCartButtonSchema","QuickActionsSchema","z.array","z.unknown","EmptyStateSchema","simRelCatalog","GengageSimRel","BaseWidget","config","ga.trackInit","newSku","simRelProduct","ga.trackProductDetail","sessionId","dispatch","params","ga.trackCartAdd","basketAddEvent","loading","spinner","requestId","fetchStart","streamStartEvent","simReq","skus","p","groupsSpec","renderedGroups","ga.trackShow","streamDoneEvent","n","g","widgetHistorySnapshotEvent","gridSpec","renderedGrid","err","getGlobalErrorMessage","streamErrorEvent","errorEl","msgEl","retryBtn","baseRegistry","mergeUISpecRegistry","defaultRender","inputSpec","inputContext","override","children","id","createSimRelWidget"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gengage/assistant-fe",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Source-available frontend widgets for Gengage AI Assistant — chat, Q&A, and similar-products. Backend is SaaS (gengage.ai).",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -1,2 +0,0 @@
1
- "use strict";const V=require("./index-VgLdYuZV.cjs"),K=require("./qna.cjs"),$=require("./simrel.cjs"),s=require("./schemas-DIyHm5pa.cjs"),b=s.object({enabled:s.boolean().default(!0)}),G=s.object({chat:s.string().optional(),qna:s.string().optional(),simrel:s.string().optional()}),Y=s.object({}),k=s._enum(["none","x-api-key-header","bearer-header","body-api-key"]),J=s.object({mode:k.default("none"),key:s.string().optional(),headerName:s.string().optional(),bodyField:s.string().default("api_key")}),X=s.object({enabled:s.boolean().default(!0),endpoint:s.string().default("/analytics"),auth:J.default({mode:"none",bodyField:"api_key"}),fireAndForget:s.boolean().default(!0),useBeacon:s.boolean().default(!0),keepaliveFetch:s.boolean().default(!0),timeoutMs:s.number().int().positive().default(4e3),maxRetries:s.number().int().min(0).max(5).default(1)}),E="__gengageWidgetsInit",z=s.object({idempotencyKey:s.string().default(E),requireDomReady:s.boolean().default(!0)}),R=s._enum(["log-and-ignore","throw","delegate"]),Z=s.object({unknownActionPolicy:R.default("log-and-ignore"),allowScriptCall:s.boolean().default(!1)}),N=s.object({version:s.literal("1",{error:'version must be "1"'}),accountId:s.string({error:"accountId must be a non-empty string"}).min(1,{error:"accountId must be a non-empty string"}),middlewareUrl:s.string({error:'middlewareUrl must be a valid URL (e.g. "https://your-backend.example.com")'}).url({error:'middlewareUrl must be a valid URL (e.g. "https://your-backend.example.com")'}),locale:s.string().optional(),widgets:s.object({chat:b.default({enabled:!0}),qna:b.default({enabled:!0}),simrel:b.default({enabled:!0})}),mounts:G.default({}),transport:Y.default({}),analytics:X.default({enabled:!0,endpoint:"/analytics",auth:{mode:"none",bodyField:"api_key"},fireAndForget:!0,useBeacon:!0,keepaliveFetch:!0,timeoutMs:4e3,maxRetries:1}),gtm:z.default({idempotencyKey:"__gengageWidgetsInit",requireDomReady:!0}),actionHandling:Z.default({unknownActionPolicy:"log-and-ignore",allowScriptCall:!1})});function U(n){s.debugLog("config","parsing account runtime config",n);const e=N.parse(n);return s.debugLog("config","config resolved",{accountId:e.accountId,middlewareUrl:e.middlewareUrl}),e}function ee(n){return N.safeParse(n)}function te(n){return U({version:"1",accountId:n.accountId,middlewareUrl:n.middlewareUrl,locale:n.locale,widgets:{chat:{enabled:!0},qna:{enabled:!0},simrel:{enabled:!0}}})}const x=`${E}_overlay_`,ne="#gengage-qna",ie="#gengage-simrel";function T(){const n=window;return n.__gengageOverlayRegistry||(n.__gengageOverlayRegistry={instances:{},pending:{}}),n.__gengageOverlayRegistry}function se(n){const e={pageType:n.pageContext?.pageType??(n.sku!==void 0?"pdp":"other")},t=n.pageContext;return t?.sku!==void 0&&(e.sku=t.sku),t?.price!==void 0&&(e.price=t.price),t?.categoryTree!==void 0&&(e.categoryTree=t.categoryTree),t?.url!==void 0&&(e.url=t.url),t?.extra!==void 0&&(e.extra=t.extra),n.sku!==void 0&&(e.sku=n.sku),e}function oe(n,e){const t={...n,...e,pageType:e.pageType??n.pageType};return e.sku===void 0&&n.sku!==void 0&&(t.sku=n.sku),t}function q(n){return n instanceof HTMLElement||document.querySelector(n)?n:null}function P(n){return n.idempotencyKey??`${x}${n.accountId}`}class ae{constructor(e,t){this.options=e,this.onDestroy=t,this._chat=null,this._qna=null,this._simrel=null,this._analyticsClient=null,this._offQnaWire=null,this._destroyed=!1,this._queue=Promise.resolve(),this._warnedQnaMountMissing=!1,this._warnedSimRelMountMissing=!1,this.idempotencyKey=P(e),this.session=s.resolveSession(e.session),this._pageContext=se(e)}get chat(){return this._chat}get qna(){return this._qna}get simrel(){return this._simrel}get analyticsClient(){return this._analyticsClient}async init(){window.gengage||(window.gengage={}),window.gengage.sessionId=this.session.sessionId,window.gengage.pageContext=this._pageContext,await this._initChat(),this.options.wireQnaToChat!==!1&&(this._offQnaWire=s.wireQNAToChat()),await this._syncPdpWidgets(),window.gengage.overlay=this}openChat(e){this._chat?.open(e)}closeChat(){this._chat?.close()}async updateContext(e){this._destroyed||await this._enqueue(async()=>{this._pageContext=oe(this._pageContext,e),window.gengage||(window.gengage={}),window.gengage.pageContext=this._pageContext,this._chat?.update(e),this._qna?.update(e),this._simrel?.update(e),await this._syncPdpWidgets()})}async updateSku(e,t="pdp"){await this.updateContext({sku:e,pageType:t})}destroy(){this._destroyed||(this._destroyed=!0,this._offQnaWire?.(),this._offQnaWire=null,this._chat?.destroy(),this._qna?.destroy(),this._simrel?.destroy(),this._chat=null,this._qna=null,this._simrel=null,window.gengage?.overlay===this&&delete window.gengage.overlay,this.onDestroy())}async _initChat(){if(this.options.chat?.enabled===!1)return;const e=this.options.middlewareUrl,t={accountId:this.options.accountId,middlewareUrl:e,session:this.session,pageContext:this._pageContext,variant:this.options.chat?.variant??"floating"};this.options.theme!==void 0&&(t.theme=this.options.theme),this.options.locale!==void 0&&(t.locale=this.options.locale),this.options.pricing!==void 0&&(t.pricing=this.options.pricing),this.options.chat?.mountTarget!==void 0&&(t.mountTarget=this.options.chat.mountTarget),this.options.chat?.launcherSvg!==void 0&&(t.launcherSvg=this.options.chat.launcherSvg),this.options.chat?.headerTitle!==void 0&&(t.headerTitle=this.options.chat.headerTitle),this.options.chat?.headerAvatarUrl!==void 0&&(t.headerAvatarUrl=this.options.chat.headerAvatarUrl),this.options.chat?.headerBadge!==void 0&&(t.headerBadge=this.options.chat.headerBadge),this.options.chat?.headerCartUrl!==void 0&&(t.headerCartUrl=this.options.chat.headerCartUrl),this.options.chat?.headerFavoritesToggle!==void 0&&(t.headerFavoritesToggle=this.options.chat.headerFavoritesToggle),this.options.chat?.hideMobileLauncher!==void 0&&(t.hideMobileLauncher=this.options.chat.hideMobileLauncher),this.options.chat?.mobileBreakpoint!==void 0&&(t.mobileBreakpoint=this.options.chat.mobileBreakpoint),this.options.chat?.mobileInitialState!==void 0&&(t.mobileInitialState=this.options.chat.mobileInitialState),this.options.chat?.i18n!==void 0&&(t.i18n=this.options.chat.i18n),this.options.chat?.actionHandling!==void 0&&(t.actionHandling=this.options.chat.actionHandling),this.options.onScriptCall!==void 0&&(t.onScriptCall=this.options.onScriptCall),this._chat=new V.GengageChat,await this._chat.init(t)}async _syncPdpWidgets(){if(this._destroyed)return;const e=this._pageContext.sku;if(!(this._pageContext.pageType==="pdp"&&e!==void 0&&e.length>0)){this._destroyPdpWidgets();return}const r=this.options.middlewareUrl;if(this.options.qna?.enabled!==!1){const o=this.options.qna?.mountTarget??ne,i=q(o);if(i)if(this._warnedQnaMountMissing=!1,this._qna)this._qna.show(),this._qna.update({pageType:"pdp",sku:e});else{const h=new K.GengageQNA,a={accountId:this.options.accountId,middlewareUrl:r,session:this.session,pageContext:{pageType:"pdp",sku:e},mountTarget:i};this.options.theme!==void 0&&(a.theme=this.options.theme),this.options.qna?.ctaText!==void 0&&(a.ctaText=this.options.qna.ctaText),this.options.qna?.inputPlaceholder!==void 0&&(a.inputPlaceholder=this.options.qna.inputPlaceholder),await h.init(a),this._qna=h}else this._qna?.destroy(),this._qna=null,this._warnedQnaMountMissing||(console.warn(`[gengage] QNA mount target not found: ${o}`),this._warnedQnaMountMissing=!0)}else this._qna?.destroy(),this._qna=null;if(this.options.simrel?.enabled!==!1){const o=this.options.simrel?.mountTarget??ie,i=q(o);if(i)if(this._warnedSimRelMountMissing=!1,this._simrel)this._simrel.show(),this._simrel.update({pageType:"pdp",sku:e});else{const h=new $.GengageSimRel,a={accountId:this.options.accountId,middlewareUrl:r,session:this.session,sku:e,mountTarget:i};this.options.theme!==void 0&&(a.theme=this.options.theme),this.options.pricing!==void 0&&(a.pricing=this.options.pricing),this.options.simrel?.discountType!==void 0&&(a.discountType=this.options.simrel.discountType),this.options.onAddToCart!==void 0&&(a.onAddToCart=this.options.onAddToCart),this.options.onProductNavigate!==void 0?a.onProductNavigate=this.options.onProductNavigate:a.onProductNavigate=(d,l,p)=>{s.isSafeUrl(d)&&(this._chat?.saveSession(p??this.session.sessionId,l),window.location.href=d)},await h.init(a),this._simrel=h}else this._simrel?.destroy(),this._simrel=null,this._warnedSimRelMountMissing||(console.warn(`[gengage] SimRel mount target not found: ${o}`),this._warnedSimRelMountMissing=!0)}else this._simrel?.destroy(),this._simrel=null}_destroyPdpWidgets(){this._qna?.destroy(),this._simrel?.destroy(),this._qna=null,this._simrel=null}_enqueue(e){const t=this._queue.then(e);return this._queue=t.catch(r=>{}),t}}async function W(n){const e=P(n),t=T(),r=t.instances[e];if(r)return r;const o=t.pending[e];if(o)return o;const i=new ae(n,()=>{const a=T();delete a.instances[e],delete a.pending[e]}),h=i.init().then(()=>(t.instances[e]=i,delete t.pending[e],i)).catch(a=>{throw delete t.pending[e],a});return t.pending[e]=h,h}function O(n){return T().instances[n]??null}function re(n){O(n)?.destroy()}function de(n){return`${x}${n}`}const L=["gengage:chat:open","gengage:chat:close","gengage:chat:ready","gengage:chat:add-to-cart","gengage:qna:action","gengage:qna:open-chat","gengage:similar:product-click","gengage:similar:add-to-cart","gengage:global:error","gengage:context:update"],ce=32,S="#gengage-qna",M="#gengage-simrel";function le(n){let e=n;if(typeof n=="string"){const i=n.trim();if(i.length===0)return null;if(!i.startsWith("{")&&!i.startsWith("["))return{type:i};try{e=JSON.parse(i)}catch{return null}}if(!e||typeof e!="object")return null;const t=e,r=[t.type,t.command,t.action,t.event].find(i=>typeof i=="string"&&i.length>0);if(!r)return null;let o=t.payload;if(o===void 0&&"data"in t&&(o=t.data),r==="setSession"&&o===void 0){const i={};typeof t.sessionId=="string"&&(i.sessionId=t.sessionId),typeof t.userId=="string"&&(i.userId=t.userId),(i.sessionId!==void 0||i.userId!==void 0)&&(o=i)}return o===void 0?{type:r}:{type:r,payload:o}}function ge(n){if(typeof n=="string"&&n.length>0)return{sku:n};if(n&&typeof n=="object"&&"sku"in n){const e=n.sku;if(typeof e=="string"&&e.length>0){const t=n.pageType;return t!==void 0?{sku:e,pageType:t}:{sku:e}}}return null}function C(n,e){return e instanceof HTMLElement?!0:typeof e!="string"?!1:n.document.querySelector(e)!==null}function A(n,e,t){if(e instanceof HTMLElement||C(n,e)||typeof e!="string")return e;if(e.startsWith("#")){const i=e.slice(1);if(i.length>0){const h=n.document.getElementById(i);if(h)return h;const a=n.document.createElement("div");return a.id=i,n.document.body.appendChild(a),a}}const r=n.document.getElementById(t);if(r)return r;const o=n.document.createElement("div");return o.id=t,n.document.body.appendChild(o),o}function B(n,e){const t=n.webkit?.messageHandlers?.[e];return t&&typeof t.postMessage=="function"?t.postMessage.bind(t):null}function v(n,e){const t=n[e];return t&&typeof t=="object"&&typeof t.postMessage=="function"?t:null}function D(n={}){const e=n.win??window,t=n.iosHandlerName??"gengage",r=n.androidInterfaceName??"GengageNative",o=n.reactNativeInterfaceName??"ReactNativeWebView";return B(e,t)?"ios":v(e,r)?"android":v(e,o)?"react-native":"browser"}function F(n,e={}){const t=e.win??window;if(n.sessionId!==void 0){t.__gengageSessionId=n.sessionId,t.gengage||(t.gengage={}),t.gengage.sessionId=n.sessionId;try{t.sessionStorage.setItem("gengage_session_id",n.sessionId)}catch{}}if(n.userId!==void 0){t.gengage||(t.gengage={});const r=t.gengage,o=r.session??{};o.userId=n.userId,r.session=o}}function j(n={}){const e=n.win??window,t=e;if(t.gengageNative)return t.gengageNative;const r=n.iosHandlerName??"gengage",o=n.androidInterfaceName??"GengageNative",i=n.reactNativeInterfaceName??"ReactNativeWebView",h=n.trackedEvents??[...L],a=D({win:e,iosHandlerName:r,androidInterfaceName:o,reactNativeInterfaceName:i});let d=e.gengage?.overlay??null;const l=[],p=(g,c)=>{const f=c===void 0?{type:g}:{type:g,payload:c};if(a==="ios"){B(e,r)?.(f);return}if(a==="android"){v(e,o)?.postMessage(JSON.stringify(f));return}if(a==="react-native"){v(e,i)?.postMessage(JSON.stringify(f));return}},m=g=>{const c=g.detail;!c||typeof c.namespace!="string"||typeof c.type!="string"||p("bridge_message",{namespace:c.namespace,type:c.type,payload:c.payload})};e.addEventListener("gengage:bridge:message",m);const Q=h.map(g=>{const c=f=>{const u=f.detail;p("widget_event",{event:g,detail:u})};return e.addEventListener(g,c),{event:g,handler:c}}),y=g=>{l.length>=ce&&l.shift(),l.push(g)},H=()=>{if(!d||l.length===0)return;const g=l.splice(0,l.length);for(const c of g)I(c)},I=g=>{const c=le(g);if(!c||typeof c.type!="string"){console.warn("[gengage:native-bridge] Invalid message:",g);return}const f=c.type,u=c.payload;switch(f){case"openChat":{d?d.openChat(u&&typeof u=="object"?u:u==="half"||u==="full"?{state:u}:void 0):y(c);return}case"closeChat":{d?d.closeChat():y(c);return}case"updateContext":{d&&u&&typeof u=="object"?d.updateContext(u):d?console.warn("[gengage:native-bridge] updateContext: missing payload"):y(c);return}case"updateSku":{const w=ge(u);if(d&&w){d.updateSku(w.sku,w.pageType);return}d?console.warn("[gengage:native-bridge] updateSku: missing sku"):y(c);return}case"setSession":{u&&typeof u=="object"&&F(u,{win:e});return}case"destroy":{d?.destroy();return}default:e.postMessage({gengage:"native",type:f,payload:u},e.location.origin),n.logUnhandled&&console.warn("[gengage:native-bridge] Unhandled inbound type forwarded:",f)}},_={env:a,sendToNative:p,receive:I,setController(g){d=g,H()},destroy(){e.removeEventListener("gengage:bridge:message",m);for(const g of Q)e.removeEventListener(g.event,g.handler);l.splice(0,l.length),e.gengageNative===_&&delete e.gengageNative}};return t.gengageNative=_,_}async function ue(n){const{nativeBridge:e,emitReadyEvent:t=!0,...r}=n,o=j(e),i={...r};i.onAddToCart||(i.onAddToCart=l=>{o.sendToNative("addToCart",{sku:l.sku,quantity:l.quantity,cartCode:l.cartCode})}),i.onProductNavigate||(i.onProductNavigate=(l,p,m)=>{o.sendToNative("productNavigate",{url:l,sku:p,sessionId:m})});const h=i.qna?.enabled===!0||i.qna?.mountTarget!==void 0;if(i.qna?.enabled!==!1)if(h){const l=A(window,i.qna?.mountTarget??S,"gengage-qna");i.qna={...i.qna,enabled:!0,mountTarget:l}}else C(window,S)||(i.qna={enabled:!1});const a=i.simrel?.enabled===!0||i.simrel?.mountTarget!==void 0;if(i.simrel?.enabled!==!1)if(a){const l=A(window,i.simrel?.mountTarget??M,"gengage-simrel");i.simrel={...i.simrel,enabled:!0,mountTarget:l}}else C(window,M)||(i.simrel={enabled:!1});const d=await W(i);return o.setController(d),t&&o.sendToNative("ready",{sessionId:d.session.sessionId,widgets:{chat:d.chat!==null,qna:d.qna!==null,simrel:d.simrel!==null}}),{controller:d,bridge:o,destroy(){d.destroy(),o.destroy()}}}exports.AccountRuntimeConfigSchema=N;exports.AnalyticsAuthModeSchema=k;exports.DEFAULT_NATIVE_TRACKED_EVENTS=L;exports.UnknownActionPolicySchema=R;exports.applyNativeSession=F;exports.buildOverlayIdempotencyKey=de;exports.createDefaultAccountRuntimeConfig=te;exports.createNativeWebViewBridge=j;exports.destroyOverlayWidgets=re;exports.detectNativeEnvironment=D;exports.getOverlayWidgets=O;exports.initNativeOverlayWidgets=ue;exports.initOverlayWidgets=W;exports.parseAccountRuntimeConfig=U;exports.safeParseAccountRuntimeConfig=ee;
2
- //# sourceMappingURL=index-BA7N_XOO.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-BA7N_XOO.cjs","sources":["../src/common/config-schema.ts","../src/common/overlay.ts","../src/common/native-webview.ts"],"sourcesContent":["import { z } from 'zod';\nimport { debugLog } from './debug.js';\n\nconst WidgetToggleSchema = z.object({\n enabled: z.boolean().default(true),\n});\n\nconst MountSelectorsSchema = z.object({\n chat: z.string().optional(),\n qna: z.string().optional(),\n simrel: z.string().optional(),\n});\n\nconst TransportSchema = z.object({});\n\nexport const AnalyticsAuthModeSchema = z.enum(['none', 'x-api-key-header', 'bearer-header', 'body-api-key']);\n\nconst AnalyticsAuthSchema = z.object({\n mode: AnalyticsAuthModeSchema.default('none'),\n key: z.string().optional(),\n headerName: z.string().optional(),\n bodyField: z.string().default('api_key'),\n});\n\nconst AnalyticsSchema = z.object({\n enabled: z.boolean().default(true),\n endpoint: z.string().default('/analytics'),\n auth: AnalyticsAuthSchema.default({ mode: 'none', bodyField: 'api_key' }),\n fireAndForget: z.boolean().default(true),\n useBeacon: z.boolean().default(true),\n keepaliveFetch: z.boolean().default(true),\n timeoutMs: z.number().int().positive().default(4000),\n maxRetries: z.number().int().min(0).max(5).default(1),\n});\n\nexport const DEFAULT_IDEMPOTENCY_KEY = '__gengageWidgetsInit';\n\nconst GTMSchema = z.object({\n idempotencyKey: z.string().default(DEFAULT_IDEMPOTENCY_KEY),\n requireDomReady: z.boolean().default(true),\n});\n\nexport const UnknownActionPolicySchema = z.enum(['log-and-ignore', 'throw', 'delegate']);\n\nconst ActionHandlingSchema = z.object({\n unknownActionPolicy: UnknownActionPolicySchema.default('log-and-ignore'),\n allowScriptCall: z.boolean().default(false),\n});\n\nexport const AccountRuntimeConfigSchema = z.object({\n version: z.literal('1', { error: 'version must be \"1\"' }),\n accountId: z\n .string({ error: 'accountId must be a non-empty string' })\n .min(1, { error: 'accountId must be a non-empty string' }),\n middlewareUrl: z\n .string({ error: 'middlewareUrl must be a valid URL (e.g. \"https://your-backend.example.com\")' })\n .url({ error: 'middlewareUrl must be a valid URL (e.g. \"https://your-backend.example.com\")' }),\n locale: z.string().optional(),\n widgets: z.object({\n chat: WidgetToggleSchema.default({ enabled: true }),\n qna: WidgetToggleSchema.default({ enabled: true }),\n simrel: WidgetToggleSchema.default({ enabled: true }),\n }),\n mounts: MountSelectorsSchema.default({}),\n transport: TransportSchema.default({}),\n analytics: AnalyticsSchema.default({\n enabled: true,\n endpoint: '/analytics',\n auth: { mode: 'none', bodyField: 'api_key' },\n fireAndForget: true,\n useBeacon: true,\n keepaliveFetch: true,\n timeoutMs: 4000,\n maxRetries: 1,\n }),\n gtm: GTMSchema.default({\n idempotencyKey: '__gengageWidgetsInit',\n requireDomReady: true,\n }),\n actionHandling: ActionHandlingSchema.default({\n unknownActionPolicy: 'log-and-ignore',\n allowScriptCall: false,\n }),\n});\n\nexport type AccountRuntimeConfig = z.infer<typeof AccountRuntimeConfigSchema>;\nexport type AnalyticsAuthMode = z.infer<typeof AnalyticsAuthModeSchema>;\nexport type UnknownActionPolicy = z.infer<typeof UnknownActionPolicySchema>;\n\nexport function parseAccountRuntimeConfig(input: unknown): AccountRuntimeConfig {\n debugLog('config', 'parsing account runtime config', input);\n const result = AccountRuntimeConfigSchema.parse(input);\n debugLog('config', 'config resolved', { accountId: result.accountId, middlewareUrl: result.middlewareUrl });\n return result;\n}\n\nexport function safeParseAccountRuntimeConfig(input: unknown): ReturnType<typeof AccountRuntimeConfigSchema.safeParse> {\n return AccountRuntimeConfigSchema.safeParse(input);\n}\n\nexport function createDefaultAccountRuntimeConfig(params: {\n accountId: string;\n middlewareUrl: string;\n locale?: string;\n}): AccountRuntimeConfig {\n return parseAccountRuntimeConfig({\n version: '1',\n accountId: params.accountId,\n middlewareUrl: params.middlewareUrl,\n locale: params.locale,\n widgets: {\n chat: { enabled: true },\n qna: { enabled: true },\n simrel: { enabled: true },\n },\n });\n}\n","import { GengageChat } from '../chat/index.js';\nimport type { ChatI18n, ChatWidgetConfig } from '../chat/types.js';\nimport { GengageQNA } from '../qna/index.js';\nimport type { QNAWidgetConfig } from '../qna/types.js';\nimport { GengageSimRel } from '../simrel/index.js';\nimport type { SimRelWidgetConfig } from '../simrel/types.js';\nimport { DEFAULT_IDEMPOTENCY_KEY } from './config-schema.js';\nimport { resolveSession } from './context.js';\nimport { wireQNAToChat } from './events.js';\nimport { isSafeUrl } from './safe-html.js';\nimport type { PageContext, SessionContext, WidgetTheme } from './types.js';\n\nconst DEFAULT_OVERLAY_KEY_PREFIX = `${DEFAULT_IDEMPOTENCY_KEY}_overlay_`;\nconst DEFAULT_QNA_MOUNT = '#gengage-qna';\nconst DEFAULT_SIMREL_MOUNT = '#gengage-simrel';\n\ninterface OverlayRegistryState {\n instances: Record<string, OverlayWidgetsRuntime>;\n pending: Record<string, Promise<OverlayWidgetsRuntime>>;\n}\n\ninterface WindowWithOverlayRegistry extends Window {\n __gengageOverlayRegistry?: OverlayRegistryState;\n}\n\nfunction getOverlayRegistry(): OverlayRegistryState {\n const win = window as WindowWithOverlayRegistry;\n if (!win.__gengageOverlayRegistry) {\n win.__gengageOverlayRegistry = {\n instances: {},\n pending: {},\n };\n }\n return win.__gengageOverlayRegistry;\n}\n\nfunction buildInitialPageContext(options: OverlayWidgetsOptions): PageContext {\n const base: PageContext = {\n pageType: options.pageContext?.pageType ?? (options.sku !== undefined ? 'pdp' : 'other'),\n };\n\n const incoming = options.pageContext;\n if (incoming?.sku !== undefined) base.sku = incoming.sku;\n if (incoming?.price !== undefined) base.price = incoming.price;\n if (incoming?.categoryTree !== undefined) base.categoryTree = incoming.categoryTree;\n if (incoming?.url !== undefined) base.url = incoming.url;\n if (incoming?.extra !== undefined) base.extra = incoming.extra;\n\n if (options.sku !== undefined) {\n base.sku = options.sku;\n }\n\n return base;\n}\n\nfunction mergePageContext(current: PageContext, patch: Partial<PageContext>): PageContext {\n const next: PageContext = {\n ...current,\n ...patch,\n pageType: patch.pageType ?? current.pageType,\n };\n if (patch.sku === undefined && current.sku !== undefined) {\n next.sku = current.sku;\n }\n return next;\n}\n\nfunction resolveMountTarget(target: HTMLElement | string): HTMLElement | string | null {\n if (target instanceof HTMLElement) return target;\n if (document.querySelector(target)) return target;\n return null;\n}\n\nfunction buildOverlayKey(options: OverlayWidgetsOptions): string {\n return options.idempotencyKey ?? `${DEFAULT_OVERLAY_KEY_PREFIX}${options.accountId}`;\n}\n\nexport interface OverlayChatOptions {\n enabled?: boolean;\n variant?: ChatWidgetConfig['variant'];\n mountTarget?: HTMLElement | string;\n launcherSvg?: string;\n headerTitle?: string;\n headerAvatarUrl?: string;\n headerBadge?: string;\n headerCartUrl?: string;\n headerFavoritesToggle?: boolean;\n hideMobileLauncher?: boolean;\n mobileBreakpoint?: number;\n mobileInitialState?: 'half' | 'full';\n i18n?: Partial<ChatI18n>;\n actionHandling?: ChatWidgetConfig['actionHandling'];\n}\n\nexport interface OverlayQNAOptions {\n enabled?: boolean;\n mountTarget?: HTMLElement | string;\n ctaText?: string;\n inputPlaceholder?: QNAWidgetConfig['inputPlaceholder'];\n}\n\nexport interface OverlaySimRelOptions {\n enabled?: boolean;\n mountTarget?: HTMLElement | string;\n discountType?: SimRelWidgetConfig['discountType'];\n}\n\nexport interface OverlayWidgetsOptions {\n accountId: string;\n middlewareUrl: string;\n locale?: string;\n session?: Partial<SessionContext>;\n pageContext?: Partial<PageContext>;\n sku?: string;\n theme?: WidgetTheme;\n /** Price formatting options. Defaults to Turkish locale. */\n pricing?: import('./price-formatter.js').PriceFormatConfig;\n idempotencyKey?: string;\n wireQnaToChat?: boolean;\n chat?: OverlayChatOptions;\n qna?: OverlayQNAOptions;\n simrel?: OverlaySimRelOptions;\n onAddToCart?: SimRelWidgetConfig['onAddToCart'];\n onProductNavigate?: SimRelWidgetConfig['onProductNavigate'];\n onScriptCall?: ChatWidgetConfig['onScriptCall'];\n}\n\nexport interface OverlayWidgetsController {\n readonly idempotencyKey: string;\n readonly session: SessionContext;\n readonly chat: GengageChat | null;\n readonly qna: GengageQNA | null;\n readonly simrel: GengageSimRel | null;\n /** Shared analytics client for custom event tracking (null if not configured). */\n readonly analyticsClient: import('./analytics.js').AnalyticsClient | null;\n openChat(options?: { state?: 'half' | 'full' }): void;\n closeChat(): void;\n updateContext(patch: Partial<PageContext>): Promise<void>;\n updateSku(sku: string, pageType?: PageContext['pageType']): Promise<void>;\n destroy(): void;\n}\n\nclass OverlayWidgetsRuntime implements OverlayWidgetsController {\n private _chat: GengageChat | null = null;\n private _qna: GengageQNA | null = null;\n private _simrel: GengageSimRel | null = null;\n private _analyticsClient: import('./analytics.js').AnalyticsClient | null = null;\n private _offQnaWire: (() => void) | null = null;\n private _pageContext: PageContext;\n private _destroyed = false;\n private _queue: Promise<void> = Promise.resolve();\n private _warnedQnaMountMissing = false;\n private _warnedSimRelMountMissing = false;\n\n readonly idempotencyKey: string;\n readonly session: SessionContext;\n\n constructor(\n private readonly options: OverlayWidgetsOptions,\n private readonly onDestroy: () => void,\n ) {\n this.idempotencyKey = buildOverlayKey(options);\n this.session = resolveSession(options.session);\n this._pageContext = buildInitialPageContext(options);\n }\n\n get chat(): GengageChat | null {\n return this._chat;\n }\n\n get qna(): GengageQNA | null {\n return this._qna;\n }\n\n get simrel(): GengageSimRel | null {\n return this._simrel;\n }\n\n get analyticsClient(): import('./analytics.js').AnalyticsClient | null {\n return this._analyticsClient;\n }\n\n async init(): Promise<void> {\n if (!window.gengage) window.gengage = {};\n window.gengage.sessionId = this.session.sessionId;\n window.gengage.pageContext = this._pageContext;\n\n await this._initChat();\n\n if (this.options.wireQnaToChat !== false) {\n this._offQnaWire = wireQNAToChat();\n }\n\n await this._syncPdpWidgets();\n\n window.gengage.overlay = this;\n }\n\n openChat(options?: { state?: 'half' | 'full' }): void {\n this._chat?.open(options);\n }\n\n closeChat(): void {\n this._chat?.close();\n }\n\n async updateContext(patch: Partial<PageContext>): Promise<void> {\n if (this._destroyed) return;\n await this._enqueue(async () => {\n this._pageContext = mergePageContext(this._pageContext, patch);\n\n if (!window.gengage) window.gengage = {};\n window.gengage.pageContext = this._pageContext;\n\n this._chat?.update(patch);\n this._qna?.update(patch);\n this._simrel?.update(patch);\n await this._syncPdpWidgets();\n });\n }\n\n async updateSku(sku: string, pageType: PageContext['pageType'] = 'pdp'): Promise<void> {\n await this.updateContext({ sku, pageType });\n }\n\n destroy(): void {\n if (this._destroyed) return;\n this._destroyed = true;\n\n this._offQnaWire?.();\n this._offQnaWire = null;\n\n this._chat?.destroy();\n this._qna?.destroy();\n this._simrel?.destroy();\n\n this._chat = null;\n this._qna = null;\n this._simrel = null;\n\n if (window.gengage?.overlay === this) {\n delete window.gengage.overlay;\n }\n\n this.onDestroy();\n }\n\n private async _initChat(): Promise<void> {\n if (this.options.chat?.enabled === false) return;\n\n const middlewareUrl = this.options.middlewareUrl;\n\n const config: ChatWidgetConfig = {\n accountId: this.options.accountId,\n middlewareUrl,\n session: this.session,\n pageContext: this._pageContext,\n variant: this.options.chat?.variant ?? 'floating',\n };\n\n if (this.options.theme !== undefined) config.theme = this.options.theme;\n if (this.options.locale !== undefined) config.locale = this.options.locale;\n if (this.options.pricing !== undefined) config.pricing = this.options.pricing;\n if (this.options.chat?.mountTarget !== undefined) config.mountTarget = this.options.chat.mountTarget;\n if (this.options.chat?.launcherSvg !== undefined) config.launcherSvg = this.options.chat.launcherSvg;\n if (this.options.chat?.headerTitle !== undefined) config.headerTitle = this.options.chat.headerTitle;\n if (this.options.chat?.headerAvatarUrl !== undefined) {\n config.headerAvatarUrl = this.options.chat.headerAvatarUrl;\n }\n if (this.options.chat?.headerBadge !== undefined) config.headerBadge = this.options.chat.headerBadge;\n if (this.options.chat?.headerCartUrl !== undefined) config.headerCartUrl = this.options.chat.headerCartUrl;\n if (this.options.chat?.headerFavoritesToggle !== undefined) {\n config.headerFavoritesToggle = this.options.chat.headerFavoritesToggle;\n }\n if (this.options.chat?.hideMobileLauncher !== undefined) {\n config.hideMobileLauncher = this.options.chat.hideMobileLauncher;\n }\n if (this.options.chat?.mobileBreakpoint !== undefined) {\n config.mobileBreakpoint = this.options.chat.mobileBreakpoint;\n }\n if (this.options.chat?.mobileInitialState !== undefined) {\n config.mobileInitialState = this.options.chat.mobileInitialState;\n }\n if (this.options.chat?.i18n !== undefined) config.i18n = this.options.chat.i18n;\n if (this.options.chat?.actionHandling !== undefined) {\n config.actionHandling = this.options.chat.actionHandling;\n }\n if (this.options.onScriptCall !== undefined) {\n config.onScriptCall = this.options.onScriptCall;\n }\n\n this._chat = new GengageChat();\n await this._chat.init(config);\n }\n\n private async _syncPdpWidgets(): Promise<void> {\n if (this._destroyed) return;\n const sku = this._pageContext.sku;\n const isPdp = this._pageContext.pageType === 'pdp' && sku !== undefined && sku.length > 0;\n\n if (!isPdp) {\n this._destroyPdpWidgets();\n return;\n }\n\n const middlewareUrl = this.options.middlewareUrl;\n\n if (this.options.qna?.enabled !== false) {\n const qnaTarget = this.options.qna?.mountTarget ?? DEFAULT_QNA_MOUNT;\n const mountTarget = resolveMountTarget(qnaTarget);\n\n if (mountTarget) {\n this._warnedQnaMountMissing = false;\n if (!this._qna) {\n const qna = new GengageQNA();\n const qnaConfig: QNAWidgetConfig = {\n accountId: this.options.accountId,\n middlewareUrl,\n session: this.session,\n pageContext: {\n pageType: 'pdp',\n sku,\n },\n mountTarget,\n };\n if (this.options.theme !== undefined) qnaConfig.theme = this.options.theme;\n if (this.options.qna?.ctaText !== undefined) qnaConfig.ctaText = this.options.qna.ctaText;\n if (this.options.qna?.inputPlaceholder !== undefined) {\n qnaConfig.inputPlaceholder = this.options.qna.inputPlaceholder;\n }\n await qna.init(qnaConfig);\n this._qna = qna;\n } else {\n this._qna.show();\n this._qna.update({ pageType: 'pdp', sku });\n }\n } else {\n this._qna?.destroy();\n this._qna = null;\n if (!this._warnedQnaMountMissing) {\n console.warn(`[gengage] QNA mount target not found: ${qnaTarget}`);\n this._warnedQnaMountMissing = true;\n }\n }\n } else {\n this._qna?.destroy();\n this._qna = null;\n }\n\n if (this.options.simrel?.enabled !== false) {\n const simRelTarget = this.options.simrel?.mountTarget ?? DEFAULT_SIMREL_MOUNT;\n const mountTarget = resolveMountTarget(simRelTarget);\n\n if (mountTarget) {\n this._warnedSimRelMountMissing = false;\n if (!this._simrel) {\n const simrel = new GengageSimRel();\n const simRelConfig: SimRelWidgetConfig = {\n accountId: this.options.accountId,\n middlewareUrl,\n session: this.session,\n sku,\n mountTarget,\n };\n if (this.options.theme !== undefined) simRelConfig.theme = this.options.theme;\n if (this.options.pricing !== undefined) simRelConfig.pricing = this.options.pricing;\n if (this.options.simrel?.discountType !== undefined) {\n simRelConfig.discountType = this.options.simrel.discountType;\n }\n if (this.options.onAddToCart !== undefined) {\n simRelConfig.onAddToCart = this.options.onAddToCart;\n }\n if (this.options.onProductNavigate !== undefined) {\n simRelConfig.onProductNavigate = this.options.onProductNavigate;\n } else {\n simRelConfig.onProductNavigate = (url, productSku, sessionId) => {\n if (!isSafeUrl(url)) return;\n this._chat?.saveSession(sessionId ?? this.session.sessionId, productSku);\n window.location.href = url;\n };\n }\n await simrel.init(simRelConfig);\n this._simrel = simrel;\n } else {\n this._simrel.show();\n this._simrel.update({ pageType: 'pdp', sku });\n }\n } else {\n this._simrel?.destroy();\n this._simrel = null;\n if (!this._warnedSimRelMountMissing) {\n console.warn(`[gengage] SimRel mount target not found: ${simRelTarget}`);\n this._warnedSimRelMountMissing = true;\n }\n }\n } else {\n this._simrel?.destroy();\n this._simrel = null;\n }\n }\n\n private _destroyPdpWidgets(): void {\n this._qna?.destroy();\n this._simrel?.destroy();\n this._qna = null;\n this._simrel = null;\n }\n\n private _enqueue(fn: () => Promise<void>): Promise<void> {\n const next = this._queue.then(fn);\n this._queue = next.catch((err) => {\n if (import.meta.env?.DEV) {\n console.error('[gengage:overlay] Queued operation failed:', err);\n }\n });\n return next;\n }\n}\n\n/**\n * Initialize all three widgets (chat, QNA, SimRel) in a single call.\n * Idempotent — safe to call multiple times from GTM; deduplicates by account + SKU key.\n *\n * @example\n * ```ts\n * import { initOverlayWidgets } from '@gengage/assistant-fe';\n *\n * const controller = await initOverlayWidgets({\n * accountId: 'mystore',\n * middlewareUrl: 'https://chat.gengage.ai',\n * sku: window.productSku,\n * pageContext: { pageType: 'pdp' },\n * chat: { variant: 'floating' },\n * qna: { mountTarget: '#qna-section' },\n * simrel: { mountTarget: '#similar-products' },\n * });\n * ```\n */\nexport async function initOverlayWidgets(options: OverlayWidgetsOptions): Promise<OverlayWidgetsController> {\n const key = buildOverlayKey(options);\n const registry = getOverlayRegistry();\n\n const existing = registry.instances[key];\n if (existing) return existing;\n\n const pending = registry.pending[key];\n if (pending) return pending;\n\n const runtime = new OverlayWidgetsRuntime(options, () => {\n const liveRegistry = getOverlayRegistry();\n delete liveRegistry.instances[key];\n delete liveRegistry.pending[key];\n });\n\n const runtimeInit = runtime\n .init()\n .then(() => {\n registry.instances[key] = runtime;\n delete registry.pending[key];\n return runtime;\n })\n .catch((err) => {\n delete registry.pending[key];\n throw err;\n });\n\n registry.pending[key] = runtimeInit;\n return runtimeInit;\n}\n\nexport function getOverlayWidgets(idempotencyKey: string): OverlayWidgetsController | null {\n const registry = getOverlayRegistry();\n return registry.instances[idempotencyKey] ?? null;\n}\n\nexport function destroyOverlayWidgets(idempotencyKey: string): void {\n const controller = getOverlayWidgets(idempotencyKey);\n controller?.destroy();\n}\n\nexport function buildOverlayIdempotencyKey(accountId: string): string {\n return `${DEFAULT_OVERLAY_KEY_PREFIX}${accountId}`;\n}\n","import { initOverlayWidgets } from './overlay.js';\nimport type { OverlayWidgetsController, OverlayWidgetsOptions } from './overlay.js';\nimport type { PageContext } from './types.js';\n\nexport const DEFAULT_NATIVE_TRACKED_EVENTS = [\n 'gengage:chat:open',\n 'gengage:chat:close',\n 'gengage:chat:ready',\n 'gengage:chat:add-to-cart',\n 'gengage:qna:action',\n 'gengage:qna:open-chat',\n 'gengage:similar:product-click',\n 'gengage:similar:add-to-cart',\n 'gengage:global:error',\n 'gengage:context:update',\n] as const;\n\nexport type NativeTrackedEvent = (typeof DEFAULT_NATIVE_TRACKED_EVENTS)[number];\nexport type NativeInboundMessage = 'openChat' | 'closeChat' | 'updateContext' | 'updateSku' | 'setSession' | 'destroy';\n\nexport type NativeBridgeEnvironment = 'ios' | 'android' | 'react-native' | 'browser';\n\nexport interface NativeSessionPayload {\n sessionId?: string;\n userId?: string;\n}\n\nexport interface NativeBridgeMessage {\n type: string;\n payload?: unknown;\n}\n\nexport interface NativeWebViewBridgeOptions {\n iosHandlerName?: string;\n androidInterfaceName?: string;\n reactNativeInterfaceName?: string;\n trackedEvents?: NativeTrackedEvent[] | string[];\n /** Log unhandled inbound message types to console in addition to forwarding to postMessage. */\n logUnhandled?: boolean;\n /** Injected for tests; defaults to global window. */\n win?: Window;\n}\n\nexport interface NativeWebViewBridge {\n readonly env: NativeBridgeEnvironment;\n sendToNative(type: string, payload?: unknown): void;\n receive(message: NativeBridgeMessage | string): void;\n setController(controller: OverlayWidgetsController | null): void;\n destroy(): void;\n}\n\nexport interface NativeOverlayInitOptions extends OverlayWidgetsOptions {\n nativeBridge?: Omit<NativeWebViewBridgeOptions, 'win'>;\n emitReadyEvent?: boolean;\n}\n\nexport interface NativeOverlayInitResult {\n controller: OverlayWidgetsController;\n bridge: NativeWebViewBridge;\n destroy(): void;\n}\n\nconst MAX_QUEUED_NATIVE_COMMANDS = 32;\nconst DEFAULT_NATIVE_QNA_MOUNT = '#gengage-qna';\nconst DEFAULT_NATIVE_SIMREL_MOUNT = '#gengage-simrel';\n\ninterface NativeWindow extends Window {\n webkit?: {\n messageHandlers?: Record<string, { postMessage?: (message: unknown) => void }>;\n };\n GengageNative?: {\n postMessage?: (message: string) => void;\n };\n ReactNativeWebView?: {\n postMessage?: (message: string) => void;\n };\n gengageNative?: NativeWebViewBridge;\n}\n\nfunction toNativeWindow(win: Window): NativeWindow {\n return win as NativeWindow;\n}\n\nfunction parseNativeBridgeMessage(raw: NativeBridgeMessage | string): NativeBridgeMessage | null {\n let candidate: unknown = raw;\n\n if (typeof raw === 'string') {\n const trimmed = raw.trim();\n if (trimmed.length === 0) return null;\n\n // Allow plain command strings such as \"openChat\" from native evaluateJavaScript calls.\n if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {\n return { type: trimmed };\n }\n\n try {\n candidate = JSON.parse(trimmed);\n } catch {\n return null;\n }\n }\n\n if (!candidate || typeof candidate !== 'object') return null;\n const obj = candidate as Record<string, unknown>;\n\n const typeCandidate = [obj['type'], obj['command'], obj['action'], obj['event']].find(\n (value): value is string => typeof value === 'string' && value.length > 0,\n );\n if (!typeCandidate) return null;\n\n let payload = obj['payload'];\n if (payload === undefined && 'data' in obj) payload = obj['data'];\n\n // Common native shorthand:\n // { type: \"setSession\", sessionId: \"...\", userId: \"...\" }\n if (typeCandidate === 'setSession' && payload === undefined) {\n const sessionPayload: NativeSessionPayload = {};\n if (typeof obj['sessionId'] === 'string') sessionPayload.sessionId = obj['sessionId'];\n if (typeof obj['userId'] === 'string') sessionPayload.userId = obj['userId'];\n if (sessionPayload.sessionId !== undefined || sessionPayload.userId !== undefined) {\n payload = sessionPayload;\n }\n }\n\n return payload === undefined ? { type: typeCandidate } : { type: typeCandidate, payload };\n}\n\nfunction parseUpdateSkuPayload(payload: unknown): { sku: string; pageType?: PageContext['pageType'] } | null {\n if (typeof payload === 'string' && payload.length > 0) {\n return { sku: payload };\n }\n if (payload && typeof payload === 'object' && 'sku' in payload) {\n const sku = (payload as { sku?: unknown }).sku;\n if (typeof sku === 'string' && sku.length > 0) {\n const pageType = (payload as { pageType?: PageContext['pageType'] }).pageType;\n return pageType !== undefined ? { sku, pageType } : { sku };\n }\n }\n return null;\n}\n\nfunction hasMountTarget(win: Window, target: HTMLElement | string): boolean {\n if (target instanceof HTMLElement) return true;\n if (typeof target !== 'string') return false;\n return win.document.querySelector(target) !== null;\n}\n\nfunction ensureMountTarget(\n win: Window,\n preferredTarget: HTMLElement | string,\n fallbackId: string,\n): HTMLElement | string {\n if (preferredTarget instanceof HTMLElement) return preferredTarget;\n if (hasMountTarget(win, preferredTarget)) return preferredTarget;\n if (typeof preferredTarget !== 'string') return preferredTarget;\n\n // If target is a simple #id selector, create that mount.\n if (preferredTarget.startsWith('#')) {\n const id = preferredTarget.slice(1);\n if (id.length > 0) {\n const existing = win.document.getElementById(id);\n if (existing) return existing;\n const mount = win.document.createElement('div');\n mount.id = id;\n win.document.body.appendChild(mount);\n return mount;\n }\n }\n\n const fallback = win.document.getElementById(fallbackId);\n if (fallback) return fallback;\n const mount = win.document.createElement('div');\n mount.id = fallbackId;\n win.document.body.appendChild(mount);\n return mount;\n}\n\nfunction getIosPostMessage(win: Window, handlerName: string): ((message: unknown) => void) | null {\n const handler = toNativeWindow(win).webkit?.messageHandlers?.[handlerName];\n if (handler && typeof handler.postMessage === 'function') {\n return handler.postMessage.bind(handler);\n }\n return null;\n}\n\nfunction getNamedBridge(win: Window, interfaceName: string): { postMessage: (message: string) => void } | null {\n const candidate = (win as Window & Record<string, unknown>)[interfaceName];\n if (candidate && typeof candidate === 'object') {\n const postMessage = (candidate as { postMessage?: unknown }).postMessage;\n if (typeof postMessage === 'function') {\n return candidate as { postMessage: (message: string) => void };\n }\n }\n return null;\n}\n\nexport function detectNativeEnvironment(\n options: Pick<\n NativeWebViewBridgeOptions,\n 'iosHandlerName' | 'androidInterfaceName' | 'reactNativeInterfaceName' | 'win'\n > = {},\n): NativeBridgeEnvironment {\n const win = options.win ?? window;\n const iosHandlerName = options.iosHandlerName ?? 'gengage';\n const androidInterfaceName = options.androidInterfaceName ?? 'GengageNative';\n const reactNativeInterfaceName = options.reactNativeInterfaceName ?? 'ReactNativeWebView';\n\n if (getIosPostMessage(win, iosHandlerName)) return 'ios';\n if (getNamedBridge(win, androidInterfaceName)) return 'android';\n if (getNamedBridge(win, reactNativeInterfaceName)) return 'react-native';\n return 'browser';\n}\n\n/**\n * Applies native-provided session identity so widgets can share correlation IDs\n * with the host app. Safe to call before or after widget initialization.\n */\nexport function applyNativeSession(\n payload: NativeSessionPayload,\n options: Pick<NativeWebViewBridgeOptions, 'win'> = {},\n): void {\n const win = options.win ?? window;\n\n if (payload.sessionId !== undefined) {\n win.__gengageSessionId = payload.sessionId;\n if (!win.gengage) win.gengage = {};\n win.gengage.sessionId = payload.sessionId;\n try {\n win.sessionStorage.setItem('gengage_session_id', payload.sessionId);\n } catch {\n // sessionStorage can be unavailable in restricted WebView modes.\n }\n }\n\n if (payload.userId !== undefined) {\n if (!win.gengage) win.gengage = {};\n const bag = win.gengage as unknown as Record<string, unknown>;\n const session = (bag['session'] as Record<string, unknown> | undefined) ?? {};\n session['userId'] = payload.userId;\n bag['session'] = session;\n }\n}\n\n/**\n * Installs a native WebView bridge compatible with:\n * - iOS WKWebView (`webkit.messageHandlers`)\n * - Android JavascriptInterface (`window.GengageNative`)\n * - React Native WebView (`window.ReactNativeWebView`)\n * and exposes it on `window.gengageNative`.\n */\nexport function createNativeWebViewBridge(options: NativeWebViewBridgeOptions = {}): NativeWebViewBridge {\n const win = options.win ?? window;\n const nativeWin = toNativeWindow(win);\n if (nativeWin.gengageNative) return nativeWin.gengageNative;\n\n const iosHandlerName = options.iosHandlerName ?? 'gengage';\n const androidInterfaceName = options.androidInterfaceName ?? 'GengageNative';\n const reactNativeInterfaceName = options.reactNativeInterfaceName ?? 'ReactNativeWebView';\n const trackedEvents = options.trackedEvents ?? [...DEFAULT_NATIVE_TRACKED_EVENTS];\n const env = detectNativeEnvironment({ win, iosHandlerName, androidInterfaceName, reactNativeInterfaceName });\n\n let controller: OverlayWidgetsController | null = win.gengage?.overlay ?? null;\n const queuedCommands: NativeBridgeMessage[] = [];\n\n const sendToNative = (type: string, payload?: unknown): void => {\n const message: NativeBridgeMessage = payload === undefined ? { type } : { type, payload };\n\n if (env === 'ios') {\n const postMessage = getIosPostMessage(win, iosHandlerName);\n postMessage?.(message);\n return;\n }\n\n if (env === 'android') {\n const androidBridge = getNamedBridge(win, androidInterfaceName);\n androidBridge?.postMessage(JSON.stringify(message));\n return;\n }\n\n if (env === 'react-native') {\n const reactNativeBridge = getNamedBridge(win, reactNativeInterfaceName);\n reactNativeBridge?.postMessage(JSON.stringify(message));\n return;\n }\n\n // Browser fallback: no-op. Useful when running the same integration\n // outside a native WebView (desktop QA, local dev, docs previews).\n return;\n };\n\n const bridgeMessageHandler: EventListener = (event) => {\n const detail = (event as CustomEvent<{ namespace: string; type: string; payload?: unknown }>).detail;\n if (!detail || typeof detail.namespace !== 'string' || typeof detail.type !== 'string') return;\n sendToNative('bridge_message', {\n namespace: detail.namespace,\n type: detail.type,\n payload: detail.payload,\n });\n };\n\n win.addEventListener('gengage:bridge:message', bridgeMessageHandler);\n\n const trackedEventHandlers: Array<{ event: string; handler: EventListener }> = trackedEvents.map((eventName) => {\n const handler: EventListener = (event) => {\n const detail = (event as CustomEvent<unknown>).detail;\n sendToNative('widget_event', {\n event: eventName,\n detail,\n });\n };\n win.addEventListener(eventName, handler);\n return { event: eventName, handler };\n });\n\n const queueCommand = (command: NativeBridgeMessage): void => {\n if (queuedCommands.length >= MAX_QUEUED_NATIVE_COMMANDS) {\n queuedCommands.shift();\n }\n queuedCommands.push(command);\n };\n\n const flushQueuedCommands = (): void => {\n if (!controller || queuedCommands.length === 0) return;\n const pending = queuedCommands.splice(0, queuedCommands.length);\n for (const command of pending) {\n receive(command);\n }\n };\n\n const receive = (message: NativeBridgeMessage | string): void => {\n const incoming = parseNativeBridgeMessage(message);\n if (!incoming || typeof incoming.type !== 'string') {\n console.warn('[gengage:native-bridge] Invalid message:', message);\n return;\n }\n\n const type = incoming.type as NativeInboundMessage | string;\n const payload = incoming.payload;\n\n switch (type) {\n case 'openChat': {\n if (controller) {\n controller.openChat(\n payload && typeof payload === 'object'\n ? (payload as { state?: 'half' | 'full' })\n : payload === 'half' || payload === 'full'\n ? { state: payload }\n : undefined,\n );\n } else {\n queueCommand(incoming);\n }\n return;\n }\n\n case 'closeChat': {\n if (controller) {\n controller.closeChat();\n } else {\n queueCommand(incoming);\n }\n return;\n }\n\n case 'updateContext': {\n if (controller && payload && typeof payload === 'object') {\n void controller.updateContext(payload as Partial<PageContext>);\n } else if (!controller) {\n queueCommand(incoming);\n } else {\n console.warn('[gengage:native-bridge] updateContext: missing payload');\n }\n return;\n }\n\n case 'updateSku': {\n const parsed = parseUpdateSkuPayload(payload);\n if (controller && parsed) {\n void controller.updateSku(parsed.sku, parsed.pageType);\n return;\n }\n if (!controller) {\n queueCommand(incoming);\n } else {\n console.warn('[gengage:native-bridge] updateSku: missing sku');\n }\n return;\n }\n\n case 'setSession': {\n if (payload && typeof payload === 'object') {\n applyNativeSession(payload as NativeSessionPayload, { win });\n }\n return;\n }\n\n case 'destroy': {\n controller?.destroy();\n return;\n }\n\n default: {\n win.postMessage({ gengage: 'native', type, payload }, win.location.origin);\n if (options.logUnhandled) {\n console.warn('[gengage:native-bridge] Unhandled inbound type forwarded:', type);\n }\n }\n }\n };\n\n const bridge: NativeWebViewBridge = {\n env,\n sendToNative,\n receive,\n setController(nextController) {\n controller = nextController;\n flushQueuedCommands();\n },\n destroy() {\n win.removeEventListener('gengage:bridge:message', bridgeMessageHandler);\n for (const entry of trackedEventHandlers) {\n win.removeEventListener(entry.event, entry.handler);\n }\n queuedCommands.splice(0, queuedCommands.length);\n if (toNativeWindow(win).gengageNative === bridge) {\n delete toNativeWindow(win).gengageNative;\n }\n },\n };\n\n nativeWin.gengageNative = bridge;\n return bridge;\n}\n\n/**\n * Convenience helper for mobile WebViews:\n * 1) installs native bridge\n * 2) initializes overlay widgets\n * 3) sends a `ready` message to native\n */\nexport async function initNativeOverlayWidgets(options: NativeOverlayInitOptions): Promise<NativeOverlayInitResult> {\n const { nativeBridge, emitReadyEvent = true, ...overlayOptions } = options;\n const bridge = createNativeWebViewBridge(nativeBridge);\n const resolvedOptions: OverlayWidgetsOptions = { ...overlayOptions };\n\n // Mobile-app-friendly defaults:\n // 1) translate commerce callbacks to native bridge messages by default\n // 2) avoid noisy missing-mount warnings unless PDP widgets are explicitly requested\n if (!resolvedOptions.onAddToCart) {\n resolvedOptions.onAddToCart = (params) => {\n bridge.sendToNative('addToCart', {\n sku: params.sku,\n quantity: params.quantity,\n cartCode: params.cartCode,\n });\n };\n }\n\n if (!resolvedOptions.onProductNavigate) {\n resolvedOptions.onProductNavigate = (url, sku, sessionId) => {\n bridge.sendToNative('productNavigate', {\n url,\n sku,\n sessionId,\n });\n };\n }\n\n const qnaRequested = resolvedOptions.qna?.enabled === true || resolvedOptions.qna?.mountTarget !== undefined;\n if (resolvedOptions.qna?.enabled !== false) {\n if (qnaRequested) {\n const mountTarget = ensureMountTarget(\n window,\n resolvedOptions.qna?.mountTarget ?? DEFAULT_NATIVE_QNA_MOUNT,\n 'gengage-qna',\n );\n resolvedOptions.qna = { ...resolvedOptions.qna, enabled: true, mountTarget };\n } else if (!hasMountTarget(window, DEFAULT_NATIVE_QNA_MOUNT)) {\n resolvedOptions.qna = { enabled: false };\n }\n }\n\n const simrelRequested = resolvedOptions.simrel?.enabled === true || resolvedOptions.simrel?.mountTarget !== undefined;\n if (resolvedOptions.simrel?.enabled !== false) {\n if (simrelRequested) {\n const mountTarget = ensureMountTarget(\n window,\n resolvedOptions.simrel?.mountTarget ?? DEFAULT_NATIVE_SIMREL_MOUNT,\n 'gengage-simrel',\n );\n resolvedOptions.simrel = { ...resolvedOptions.simrel, enabled: true, mountTarget };\n } else if (!hasMountTarget(window, DEFAULT_NATIVE_SIMREL_MOUNT)) {\n resolvedOptions.simrel = { enabled: false };\n }\n }\n\n const controller = await initOverlayWidgets(resolvedOptions);\n bridge.setController(controller);\n\n if (emitReadyEvent) {\n bridge.sendToNative('ready', {\n sessionId: controller.session.sessionId,\n widgets: {\n chat: controller.chat !== null,\n qna: controller.qna !== null,\n simrel: controller.simrel !== null,\n },\n });\n }\n\n return {\n controller,\n bridge,\n destroy() {\n controller.destroy();\n bridge.destroy();\n },\n };\n}\n"],"names":["WidgetToggleSchema","z.object","z.boolean","MountSelectorsSchema","z.string","TransportSchema","AnalyticsAuthModeSchema","z.enum","AnalyticsAuthSchema","AnalyticsSchema","z.number","DEFAULT_IDEMPOTENCY_KEY","GTMSchema","UnknownActionPolicySchema","ActionHandlingSchema","AccountRuntimeConfigSchema","z.literal","parseAccountRuntimeConfig","input","debugLog","result","safeParseAccountRuntimeConfig","createDefaultAccountRuntimeConfig","params","DEFAULT_OVERLAY_KEY_PREFIX","DEFAULT_QNA_MOUNT","DEFAULT_SIMREL_MOUNT","getOverlayRegistry","win","buildInitialPageContext","options","base","incoming","mergePageContext","current","patch","next","resolveMountTarget","target","buildOverlayKey","OverlayWidgetsRuntime","onDestroy","resolveSession","wireQNAToChat","sku","pageType","middlewareUrl","config","GengageChat","qnaTarget","mountTarget","qna","GengageQNA","qnaConfig","simRelTarget","simrel","GengageSimRel","simRelConfig","url","productSku","sessionId","isSafeUrl","fn","err","initOverlayWidgets","key","registry","existing","pending","runtime","liveRegistry","runtimeInit","getOverlayWidgets","idempotencyKey","destroyOverlayWidgets","buildOverlayIdempotencyKey","accountId","DEFAULT_NATIVE_TRACKED_EVENTS","MAX_QUEUED_NATIVE_COMMANDS","DEFAULT_NATIVE_QNA_MOUNT","DEFAULT_NATIVE_SIMREL_MOUNT","parseNativeBridgeMessage","raw","candidate","trimmed","obj","typeCandidate","value","payload","sessionPayload","parseUpdateSkuPayload","hasMountTarget","ensureMountTarget","preferredTarget","fallbackId","id","mount","fallback","getIosPostMessage","handlerName","handler","getNamedBridge","interfaceName","detectNativeEnvironment","iosHandlerName","androidInterfaceName","reactNativeInterfaceName","applyNativeSession","bag","session","createNativeWebViewBridge","nativeWin","trackedEvents","env","controller","queuedCommands","sendToNative","type","message","bridgeMessageHandler","event","detail","trackedEventHandlers","eventName","queueCommand","command","flushQueuedCommands","receive","parsed","bridge","nextController","entry","initNativeOverlayWidgets","nativeBridge","emitReadyEvent","overlayOptions","resolvedOptions","qnaRequested","simrelRequested"],"mappings":"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"}