@gengage/assistant-fe 0.1.9 → 0.2.1

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 (71) hide show
  1. package/dist/assistant-fe.css +1 -1
  2. package/dist/chat/components/CategoriesContainer.d.ts.map +1 -1
  3. package/dist/chat/components/ChatDrawer.d.ts.map +1 -1
  4. package/dist/chat/components/renderUISpec.d.ts.map +1 -1
  5. package/dist/chat/index.d.ts.map +1 -1
  6. package/dist/chat/panel-manager.d.ts +16 -0
  7. package/dist/chat/panel-manager.d.ts.map +1 -1
  8. package/dist/chat.cjs +1 -1
  9. package/dist/chat.iife.js +28 -28
  10. package/dist/chat.iife.js.map +1 -1
  11. package/dist/chat.js +2 -2
  12. package/dist/common/action-router.d.ts.map +1 -1
  13. package/dist/common/debug.d.ts.map +1 -1
  14. package/dist/common/events.d.ts.map +1 -1
  15. package/dist/common/native-webview.d.ts.map +1 -1
  16. package/dist/common/product-utils.d.ts +10 -0
  17. package/dist/common/product-utils.d.ts.map +1 -1
  18. package/dist/common/protocol-adapter.d.ts.map +1 -1
  19. package/dist/common.cjs +1 -1
  20. package/dist/common.js +5 -5
  21. package/dist/index-BUtw0Jlm.cjs +2 -0
  22. package/dist/index-BUtw0Jlm.cjs.map +1 -0
  23. package/dist/index-D-tVifN8.cjs +13 -0
  24. package/dist/index-D-tVifN8.cjs.map +1 -0
  25. package/dist/{index-DR2uepzb.js → index-DjPldwe7.js} +181 -187
  26. package/dist/index-DjPldwe7.js.map +1 -0
  27. package/dist/{index-CEt87kCd.js → index-TY0qKDI-.js} +1291 -1292
  28. package/dist/index-TY0qKDI-.js.map +1 -0
  29. package/dist/index.cjs +1 -1
  30. package/dist/index.js +3 -3
  31. package/dist/native.cjs +1 -1
  32. package/dist/native.iife.js +30 -30
  33. package/dist/native.iife.js.map +1 -1
  34. package/dist/native.js +1 -1
  35. package/dist/qna.cjs +1 -1
  36. package/dist/qna.iife.js +2 -2
  37. package/dist/qna.iife.js.map +1 -1
  38. package/dist/qna.js +1 -1
  39. package/dist/quantity-stepper-BKtPQUR1.js +78 -0
  40. package/dist/quantity-stepper-BKtPQUR1.js.map +1 -0
  41. package/dist/quantity-stepper-DU6va4sS.cjs +2 -0
  42. package/dist/quantity-stepper-DU6va4sS.cjs.map +1 -0
  43. package/dist/{schemas-DIhL3DkL.js → schemas-BAEbjFPE.js} +17 -12
  44. package/dist/schemas-BAEbjFPE.js.map +1 -0
  45. package/dist/{schemas-Dsr0bbO_.cjs → schemas-DIyHm5pa.cjs} +4 -4
  46. package/dist/{schemas-DIhL3DkL.js.map → schemas-DIyHm5pa.cjs.map} +1 -1
  47. package/dist/simrel/api.d.ts.map +1 -1
  48. package/dist/simrel/components/ProductCard.d.ts.map +1 -1
  49. package/dist/simrel/locales/en.d.ts.map +1 -1
  50. package/dist/simrel/locales/tr.d.ts.map +1 -1
  51. package/dist/simrel/types.d.ts +1 -0
  52. package/dist/simrel/types.d.ts.map +1 -1
  53. package/dist/simrel.cjs +1 -1
  54. package/dist/simrel.cjs.map +1 -1
  55. package/dist/simrel.css +1 -1
  56. package/dist/simrel.iife.js +6 -6
  57. package/dist/simrel.iife.js.map +1 -1
  58. package/dist/simrel.js +236 -234
  59. package/dist/simrel.js.map +1 -1
  60. package/package.json +1 -1
  61. package/dist/index-BWPx4pM7.cjs +0 -13
  62. package/dist/index-BWPx4pM7.cjs.map +0 -1
  63. package/dist/index-CEt87kCd.js.map +0 -1
  64. package/dist/index-DL4CAkyL.cjs +0 -2
  65. package/dist/index-DL4CAkyL.cjs.map +0 -1
  66. package/dist/index-DR2uepzb.js.map +0 -1
  67. package/dist/quantity-stepper-C-nV4lwi.js +0 -77
  68. package/dist/quantity-stepper-C-nV4lwi.js.map +0 -1
  69. package/dist/quantity-stepper-CURMkwRF.cjs +0 -2
  70. package/dist/quantity-stepper-CURMkwRF.cjs.map +0 -1
  71. package/dist/schemas-Dsr0bbO_.cjs.map +0 -1
@@ -1,2 +0,0 @@
1
- "use strict";const $=require("./index-BWPx4pM7.cjs"),G=require("./qna.cjs"),Y=require("./simrel.cjs"),s=require("./schemas-Dsr0bbO_.cjs"),w=s.object({enabled:s.boolean().default(!0)}),J=s.object({chat:s.string().optional(),qna:s.string().optional(),simrel:s.string().optional()}),X=s.object({}),M=s._enum(["none","x-api-key-header","bearer-header","body-api-key"]),z=s.object({mode:M.default("none"),key:s.string().optional(),headerName:s.string().optional(),bodyField:s.string().default("api_key")}),Z=s.object({enabled:s.boolean().default(!0),endpoint:s.string().default("/analytics"),auth:z.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)}),k="__gengageWidgetsInit",ee=s.object({idempotencyKey:s.string().default(k),requireDomReady:s.boolean().default(!0)}),E=s._enum(["log-and-ignore","throw","delegate"]),te=s.object({unknownActionPolicy:E.default("log-and-ignore"),allowScriptCall:s.boolean().default(!1)}),C=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:w.default({enabled:!0}),qna:w.default({enabled:!0}),simrel:w.default({enabled:!0})}),mounts:J.default({}),transport:X.default({}),analytics:Z.default({enabled:!0,endpoint:"/analytics",auth:{mode:"none",bodyField:"api_key"},fireAndForget:!0,useBeacon:!0,keepaliveFetch:!0,timeoutMs:4e3,maxRetries:1}),gtm:ee.default({idempotencyKey:"__gengageWidgetsInit",requireDomReady:!0}),actionHandling:te.default({unknownActionPolicy:"log-and-ignore",allowScriptCall:!1})});function R(t){s.debugLog("config","parsing account runtime config",t);const e=C.parse(t);return s.debugLog("config","config resolved",{accountId:e.accountId,middlewareUrl:e.middlewareUrl}),e}function ne(t){return C.safeParse(t)}function ie(t){return R({version:"1",accountId:t.accountId,middlewareUrl:t.middlewareUrl,locale:t.locale,widgets:{chat:{enabled:!0},qna:{enabled:!0},simrel:{enabled:!0}}})}const U=`${k}_overlay_`,se="#gengage-qna",oe="#gengage-simrel";function b(){const t=window;return t.__gengageOverlayRegistry||(t.__gengageOverlayRegistry={instances:{},pending:{}}),t.__gengageOverlayRegistry}function ae(t){const e={pageType:t.pageContext?.pageType??(t.sku!==void 0?"pdp":"other")},n=t.pageContext;return n?.sku!==void 0&&(e.sku=n.sku),n?.price!==void 0&&(e.price=n.price),n?.categoryTree!==void 0&&(e.categoryTree=n.categoryTree),n?.url!==void 0&&(e.url=n.url),n?.extra!==void 0&&(e.extra=n.extra),t.sku!==void 0&&(e.sku=t.sku),e}function re(t,e){const n={...t,...e,pageType:e.pageType??t.pageType};return e.sku===void 0&&t.sku!==void 0&&(n.sku=t.sku),n}function I(t){return t instanceof HTMLElement||document.querySelector(t)?t:null}function x(t){return t.idempotencyKey??`${U}${t.accountId}`}class de{constructor(e,n){this.options=e,this.onDestroy=n,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=x(e),this.session=s.resolveSession(e.session),this._pageContext=ae(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=re(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,n="pdp"){await this.updateContext({sku:e,pageType:n})}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,n={accountId:this.options.accountId,middlewareUrl:e,session:this.session,pageContext:this._pageContext,variant:this.options.chat?.variant??"floating"};this.options.theme!==void 0&&(n.theme=this.options.theme),this.options.locale!==void 0&&(n.locale=this.options.locale),this.options.pricing!==void 0&&(n.pricing=this.options.pricing),this.options.chat?.mountTarget!==void 0&&(n.mountTarget=this.options.chat.mountTarget),this.options.chat?.launcherSvg!==void 0&&(n.launcherSvg=this.options.chat.launcherSvg),this.options.chat?.headerTitle!==void 0&&(n.headerTitle=this.options.chat.headerTitle),this.options.chat?.headerAvatarUrl!==void 0&&(n.headerAvatarUrl=this.options.chat.headerAvatarUrl),this.options.chat?.headerBadge!==void 0&&(n.headerBadge=this.options.chat.headerBadge),this.options.chat?.headerCartUrl!==void 0&&(n.headerCartUrl=this.options.chat.headerCartUrl),this.options.chat?.headerFavoritesToggle!==void 0&&(n.headerFavoritesToggle=this.options.chat.headerFavoritesToggle),this.options.chat?.hideMobileLauncher!==void 0&&(n.hideMobileLauncher=this.options.chat.hideMobileLauncher),this.options.chat?.mobileBreakpoint!==void 0&&(n.mobileBreakpoint=this.options.chat.mobileBreakpoint),this.options.chat?.mobileInitialState!==void 0&&(n.mobileInitialState=this.options.chat.mobileInitialState),this.options.chat?.i18n!==void 0&&(n.i18n=this.options.chat.i18n),this.options.chat?.actionHandling!==void 0&&(n.actionHandling=this.options.chat.actionHandling),this.options.onScriptCall!==void 0&&(n.onScriptCall=this.options.onScriptCall),this._chat=new $.GengageChat,await this._chat.init(n)}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??se,i=I(o);if(i)if(this._warnedQnaMountMissing=!1,this._qna)this._qna.show(),this._qna.update({pageType:"pdp",sku:e});else{const h=new G.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??oe,i=I(o);if(i)if(this._warnedSimRelMountMissing=!1,this._simrel)this._simrel.show(),this._simrel.update({pageType:"pdp",sku:e});else{const h=new Y.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 n=this._queue.then(e);return this._queue=n.catch(r=>{}),n}}async function P(t){const e=x(t),n=b(),r=n.instances[e];if(r)return r;const o=n.pending[e];if(o)return o;const i=new de(t,()=>{const a=b();delete a.instances[e],delete a.pending[e]}),h=i.init().then(()=>(n.instances[e]=i,delete n.pending[e],i)).catch(a=>{throw delete n.pending[e],a});return n.pending[e]=h,h}function W(t){return b().instances[t]??null}function ce(t){W(t)?.destroy()}function le(t){return`${U}${t}`}const O=["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"],ge=32,q="#gengage-qna",S="#gengage-simrel";function ue(t){let e=t;if(typeof t=="string"){const i=t.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 n=e,r=[n.type,n.command,n.action,n.event].find(i=>typeof i=="string"&&i.length>0);if(!r)return null;let o=n.payload;if(o===void 0&&"data"in n&&(o=n.data),r==="setSession"&&o===void 0){const i={};typeof n.sessionId=="string"&&(i.sessionId=n.sessionId),typeof n.userId=="string"&&(i.userId=n.userId),(i.sessionId!==void 0||i.userId!==void 0)&&(o=i)}return o===void 0?{type:r}:{type:r,payload:o}}function he(t){if(typeof t=="string"&&t.length>0)return{sku:t};if(t&&typeof t=="object"&&"sku"in t){const e=t.sku;if(typeof e=="string"&&e.length>0){const n=t.pageType;return n!==void 0?{sku:e,pageType:n}:{sku:e}}}return null}function T(t,e){return e instanceof HTMLElement?!0:typeof e!="string"?!1:t.document.querySelector(e)!==null}function A(t,e,n){if(e instanceof HTMLElement||T(t,e)||typeof e!="string")return e;if(e.startsWith("#")){const i=e.slice(1);if(i.length>0){const h=t.document.getElementById(i);if(h)return h;const a=t.document.createElement("div");return a.id=i,t.document.body.appendChild(a),a}}const r=t.document.getElementById(n);if(r)return r;const o=t.document.createElement("div");return o.id=n,t.document.body.appendChild(o),o}function L(t,e){const n=t.webkit?.messageHandlers?.[e];return n&&typeof n.postMessage=="function"?n.postMessage.bind(n):null}function B(t,e){const n=t[e];return n&&typeof n=="object"&&typeof n.postMessage=="function"?n:null}function D(t,e){return B(t,e)}function F(t,e){return B(t,e)}function j(t={}){const e=t.win??window,n=t.iosHandlerName??"gengage",r=t.androidInterfaceName??"GengageNative",o=t.reactNativeInterfaceName??"ReactNativeWebView";return L(e,n)?"ios":D(e,r)?"android":F(e,o)?"react-native":"browser"}function Q(t,e={}){const n=e.win??window;if(t.sessionId!==void 0){n.__gengageSessionId=t.sessionId,n.gengage||(n.gengage={}),n.gengage.sessionId=t.sessionId;try{n.sessionStorage.setItem("gengage_session_id",t.sessionId)}catch{}}if(t.userId!==void 0){n.gengage||(n.gengage={});const r=n.gengage,o=r.session??{};o.userId=t.userId,r.session=o}}function H(t={}){const e=t.win??window,n=e;if(n.gengageNative)return n.gengageNative;const r=t.iosHandlerName??"gengage",o=t.androidInterfaceName??"GengageNative",i=t.reactNativeInterfaceName??"ReactNativeWebView",h=t.trackedEvents??[...O],a=j({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"){L(e,r)?.(f);return}if(a==="android"){D(e,o)?.postMessage(JSON.stringify(f));return}if(a==="react-native"){F(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 V=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>=ge&&l.shift(),l.push(g)},K=()=>{if(!d||l.length===0)return;const g=l.splice(0,l.length);for(const c of g)N(c)},N=g=>{const c=ue(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 _=he(u);if(d&&_){d.updateSku(_.sku,_.pageType);return}d?console.warn("[gengage:native-bridge] updateSku: missing sku"):y(c);return}case"setSession":{u&&typeof u=="object"&&Q(u,{win:e});return}case"destroy":{d?.destroy();return}default:e.postMessage({gengage:"native",type:f,payload:u},e.location.origin),t.logUnhandled&&console.warn("[gengage:native-bridge] Unhandled inbound type forwarded:",f)}},v={env:a,sendToNative:p,receive:N,setController(g){d=g,K()},destroy(){e.removeEventListener("gengage:bridge:message",m);for(const g of V)e.removeEventListener(g.event,g.handler);l.splice(0,l.length),e.gengageNative===v&&delete e.gengageNative}};return n.gengageNative=v,v}async function fe(t){const{nativeBridge:e,emitReadyEvent:n=!0,...r}=t,o=H(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??q,"gengage-qna");i.qna={...i.qna,enabled:!0,mountTarget:l}}else T(window,q)||(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??S,"gengage-simrel");i.simrel={...i.simrel,enabled:!0,mountTarget:l}}else T(window,S)||(i.simrel={enabled:!1});const d=await P(i);return o.setController(d),n&&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=C;exports.AnalyticsAuthModeSchema=M;exports.DEFAULT_NATIVE_TRACKED_EVENTS=O;exports.UnknownActionPolicySchema=E;exports.applyNativeSession=Q;exports.buildOverlayIdempotencyKey=le;exports.createDefaultAccountRuntimeConfig=ie;exports.createNativeWebViewBridge=H;exports.destroyOverlayWidgets=ce;exports.detectNativeEnvironment=j;exports.getOverlayWidgets=W;exports.initNativeOverlayWidgets=fe;exports.initOverlayWidgets=P;exports.parseAccountRuntimeConfig=R;exports.safeParseAccountRuntimeConfig=ne;
2
- //# sourceMappingURL=index-DL4CAkyL.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-DL4CAkyL.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\nfunction getAndroidBridge(win: Window, interfaceName: string): { postMessage: (message: string) => void } | null {\n return getNamedBridge(win, interfaceName);\n}\n\nfunction getReactNativeBridge(win: Window, interfaceName: string): { postMessage: (message: string) => void } | null {\n return getNamedBridge(win, interfaceName);\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 (getAndroidBridge(win, androidInterfaceName)) return 'android';\n if (getReactNativeBridge(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 = getAndroidBridge(win, androidInterfaceName);\n androidBridge?.postMessage(JSON.stringify(message));\n return;\n }\n\n if (env === 'react-native') {\n const reactNativeBridge = getReactNativeBridge(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","getAndroidBridge","getReactNativeBridge","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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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-DR2uepzb.js","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\nfunction getAndroidBridge(win: Window, interfaceName: string): { postMessage: (message: string) => void } | null {\n return getNamedBridge(win, interfaceName);\n}\n\nfunction getReactNativeBridge(win: Window, interfaceName: string): { postMessage: (message: string) => void } | null {\n return getNamedBridge(win, interfaceName);\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 (getAndroidBridge(win, androidInterfaceName)) return 'android';\n if (getReactNativeBridge(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 = getAndroidBridge(win, androidInterfaceName);\n androidBridge?.postMessage(JSON.stringify(message));\n return;\n }\n\n if (env === 'react-native') {\n const reactNativeBridge = getReactNativeBridge(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","getAndroidBridge","getReactNativeBridge","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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"}
@@ -1,77 +0,0 @@
1
- const f = {
2
- currencySymbol: "TL",
3
- currencyPosition: "suffix",
4
- thousandsSeparator: ".",
5
- decimalSeparator: ",",
6
- alwaysShowDecimals: !1
7
- };
8
- function x(t, b) {
9
- const r = Number(t);
10
- if (!Number.isFinite(r) || r < 0) return t;
11
- const e = { ...f, ...b }, o = r % 1 !== 0 || e.alwaysShowDecimals ? r.toFixed(2) : r.toFixed(0), l = o.indexOf("."), c = l === -1 ? o : o.slice(0, l), i = l === -1 ? void 0 : o.slice(l + 1), s = c.replace(/\B(?=(\d{3})+(?!\d))/g, e.thousandsSeparator);
12
- let a;
13
- return i !== void 0 ? a = `${s}${e.decimalSeparator}${i}` : a = s, e.currencySymbol ? e.currencyPosition === "prefix" ? `${e.currencySymbol}${a}` : `${a} ${e.currencySymbol}` : a;
14
- }
15
- function y(t) {
16
- return Number.isFinite(t) ? Math.max(0, Math.min(5, t)) : 0;
17
- }
18
- function h(t) {
19
- return Number.isFinite(t) ? Math.max(0, Math.min(100, Math.round(t))) : 0;
20
- }
21
- function S(t, b = !0) {
22
- const r = y(t);
23
- if (b) {
24
- const d = Math.floor(r), o = r - d >= 0.5 ? 1 : 0, l = 5 - d - o;
25
- return "★".repeat(d) + (o ? "½" : "") + "☆".repeat(l);
26
- }
27
- const e = Math.round(r);
28
- return "★".repeat(e) + "☆".repeat(5 - e);
29
- }
30
- function C(t) {
31
- t.addEventListener(
32
- "error",
33
- () => {
34
- t.style.display = "none";
35
- },
36
- { once: !0 }
37
- );
38
- }
39
- function E(t) {
40
- const b = t.min ?? 1, r = t.max ?? 99, e = Math.min(b, r), d = Math.max(b, r), o = Math.max(e, Math.min(d, t.initial ?? e)), l = t.compact ?? !1;
41
- let c = o;
42
- const i = document.createElement("div");
43
- i.className = `gengage-qty-stepper${l ? " gengage-qty-stepper--compact" : ""}`;
44
- const s = document.createElement("button");
45
- s.className = "gengage-qty-btn", s.type = "button", s.textContent = t.decreaseSymbol ?? "−", s.setAttribute("aria-label", t.decreaseLabel ?? "Decrease");
46
- const a = document.createElement("span");
47
- a.className = "gengage-qty-value", a.textContent = String(c), a.setAttribute("aria-live", "polite"), a.setAttribute("aria-atomic", "true");
48
- const u = document.createElement("button");
49
- u.className = "gengage-qty-btn", u.type = "button", u.textContent = t.increaseSymbol ?? "+", u.setAttribute("aria-label", t.increaseLabel ?? "Increase");
50
- const n = document.createElement("button");
51
- n.className = "gengage-qty-submit", n.type = "button", l ? (n.textContent = t.submitIcon ?? "🛒", n.title = t.label ?? "Add to Cart") : n.textContent = t.label ?? "Add to Cart";
52
- function p() {
53
- s.disabled = c <= e, u.disabled = c >= d;
54
- }
55
- return s.addEventListener("click", (m) => {
56
- m.stopPropagation(), c > e && (c--, a.textContent = String(c), p());
57
- }), u.addEventListener("click", (m) => {
58
- m.stopPropagation(), c < d && (c++, a.textContent = String(c), p());
59
- }), n.addEventListener("click", (m) => {
60
- m.stopPropagation(), t.onSubmit(c);
61
- const g = n.textContent;
62
- n.textContent = "✓", n.classList.add("gengage-qty-submit--success"), n.disabled = !0, setTimeout(() => {
63
- n.textContent = g, n.classList.remove("gengage-qty-submit--success"), n.disabled = !1;
64
- }, 1200);
65
- }), i.addEventListener("click", (m) => {
66
- m.stopPropagation();
67
- }), p(), i.appendChild(s), i.appendChild(a), i.appendChild(u), i.appendChild(n), i;
68
- }
69
- export {
70
- C as a,
71
- E as b,
72
- h as c,
73
- y as d,
74
- x as f,
75
- S as r
76
- };
77
- //# sourceMappingURL=quantity-stepper-C-nV4lwi.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"quantity-stepper-C-nV4lwi.js","sources":["../src/common/price-formatter.ts","../src/common/product-utils.ts","../src/common/quantity-stepper.ts"],"sourcesContent":["/**\n * Configurable price formatting.\n *\n * Defaults to Turkish locale (dot thousands, comma decimal, TL suffix).\n * Configure via widget config `pricing` field for any locale/currency.\n */\n\nexport interface PriceFormatConfig {\n /** Currency symbol. Default: 'TL' */\n currencySymbol?: string;\n /** Where to place the symbol. Default: 'suffix' */\n currencyPosition?: 'prefix' | 'suffix';\n /** Separator between thousands. Default: '.' (Turkish) */\n thousandsSeparator?: string;\n /** Decimal point character. Default: ',' (Turkish) */\n decimalSeparator?: string;\n /** Whether to show decimal part for whole numbers. Default: false */\n alwaysShowDecimals?: boolean;\n}\n\nconst TURKISH_DEFAULTS: Required<PriceFormatConfig> = {\n currencySymbol: 'TL',\n currencyPosition: 'suffix',\n thousandsSeparator: '.',\n decimalSeparator: ',',\n alwaysShowDecimals: false,\n};\n\n/**\n * Formats a raw numeric price string into the configured locale format.\n *\n * Examples (default Turkish):\n * \"17990\" → \"17.990 TL\"\n * \"17990.5\" → \"17.990,50 TL\"\n *\n * Examples (GBP prefix):\n * \"17990\" with { currencySymbol: '£', currencyPosition: 'prefix', thousandsSeparator: ',', decimalSeparator: '.' }\n * → \"£17,990\"\n *\n * Returns the input as-is if it's not a valid number.\n */\nexport function formatPrice(raw: string, config?: PriceFormatConfig): string {\n const num = Number(raw);\n if (!Number.isFinite(num) || num < 0) return raw;\n\n const resolved = { ...TURKISH_DEFAULTS, ...config };\n\n const hasDecimals = num % 1 !== 0;\n const fixed = hasDecimals || resolved.alwaysShowDecimals ? num.toFixed(2) : num.toFixed(0);\n const dotIdx = fixed.indexOf('.');\n const intPart = dotIdx === -1 ? fixed : fixed.slice(0, dotIdx);\n const decPart = dotIdx === -1 ? undefined : fixed.slice(dotIdx + 1);\n\n // Add thousands separators to integer part\n const withSeparators = intPart.replace(/\\B(?=(\\d{3})+(?!\\d))/g, resolved.thousandsSeparator);\n\n let formatted: string;\n if (decPart !== undefined) {\n formatted = `${withSeparators}${resolved.decimalSeparator}${decPart}`;\n } else {\n formatted = withSeparators;\n }\n\n if (resolved.currencySymbol) {\n if (resolved.currencyPosition === 'prefix') {\n return `${resolved.currencySymbol}${formatted}`;\n }\n return `${formatted} ${resolved.currencySymbol}`;\n }\n\n return formatted;\n}\n","/**\n * Shared product rendering utilities.\n *\n * Extracted from chat/renderUISpec and simrel/ProductCard to eliminate\n * duplication and provide consistent behavior across all widgets.\n */\n\n/** Clamp a rating value to the 0–5 range. Returns 0 for NaN/non-finite. */\nexport function clampRating(value: number): number {\n if (!Number.isFinite(value)) return 0;\n return Math.max(0, Math.min(5, value));\n}\n\n/** Clamp a discount percentage to the 0–100 range, rounded to integer. Returns 0 for NaN/non-finite. */\nexport function clampDiscount(value: number): number {\n if (!Number.isFinite(value)) return 0;\n return Math.max(0, Math.min(100, Math.round(value)));\n}\n\n/**\n * Render a star rating string with full, half, and empty stars.\n *\n * @param rating - A numeric rating (will be clamped to 0–5).\n * @param halfStars - Whether to render half-star characters. Defaults to true.\n * @returns A string like \"★★★½☆\" or \"★★★☆☆\" (without half-stars).\n */\nexport function renderStarRating(rating: number, halfStars: boolean = true): string {\n const clamped = clampRating(rating);\n if (halfStars) {\n const full = Math.floor(clamped);\n const half = clamped - full >= 0.5 ? 1 : 0;\n const empty = 5 - full - half;\n return '\\u2605'.repeat(full) + (half ? '\\u00BD' : '') + '\\u2606'.repeat(empty);\n }\n const rounded = Math.round(clamped);\n return '\\u2605'.repeat(rounded) + '\\u2606'.repeat(5 - rounded);\n}\n\n/**\n * Attach a one-time error handler that hides the image on load failure.\n *\n * Works with any HTMLImageElement. Hides the element by setting\n * `display: none` so layout doesn't break from broken images.\n */\nexport function addImageErrorHandler(img: HTMLImageElement): void {\n img.addEventListener(\n 'error',\n () => {\n img.style.display = 'none';\n },\n { once: true },\n );\n}\n","export interface QuantityStepperOptions {\n min?: number | undefined;\n max?: number | undefined;\n initial?: number | undefined;\n label?: string | undefined;\n compact?: boolean | undefined;\n decreaseLabel?: string | undefined;\n increaseLabel?: string | undefined;\n /** Symbol for decrease button (default: '\\u2212' minus sign). */\n decreaseSymbol?: string | undefined;\n /** Symbol for increase button (default: '+'). */\n increaseSymbol?: string | undefined;\n /** Icon/text for compact mode submit button (default: shopping cart emoji). */\n submitIcon?: string | undefined;\n onSubmit: (quantity: number) => void;\n}\n\n/**\n * Creates a quantity stepper with [−] [value] [+] and a submit button.\n * Compact mode renders a cart icon button; full mode renders a labeled button.\n */\nexport function createQuantityStepper(options: QuantityStepperOptions): HTMLElement {\n const rawMin = options.min ?? 1;\n const rawMax = options.max ?? 99;\n // Ensure min <= max; swap if caller provided inverted range\n const min = Math.min(rawMin, rawMax);\n const max = Math.max(rawMin, rawMax);\n const initial = Math.max(min, Math.min(max, options.initial ?? min));\n const compact = options.compact ?? false;\n\n let quantity = initial;\n\n const container = document.createElement('div');\n container.className = `gengage-qty-stepper${compact ? ' gengage-qty-stepper--compact' : ''}`;\n\n const decBtn = document.createElement('button');\n decBtn.className = 'gengage-qty-btn';\n decBtn.type = 'button';\n decBtn.textContent = options.decreaseSymbol ?? '\\u2212'; // minus sign\n decBtn.setAttribute('aria-label', options.decreaseLabel ?? 'Decrease');\n\n const valueEl = document.createElement('span');\n valueEl.className = 'gengage-qty-value';\n valueEl.textContent = String(quantity);\n valueEl.setAttribute('aria-live', 'polite');\n valueEl.setAttribute('aria-atomic', 'true');\n\n const incBtn = document.createElement('button');\n incBtn.className = 'gengage-qty-btn';\n incBtn.type = 'button';\n incBtn.textContent = options.increaseSymbol ?? '+';\n incBtn.setAttribute('aria-label', options.increaseLabel ?? 'Increase');\n\n const submitBtn = document.createElement('button');\n submitBtn.className = 'gengage-qty-submit';\n submitBtn.type = 'button';\n\n if (compact) {\n submitBtn.textContent = options.submitIcon ?? '\\uD83D\\uDED2'; // shopping cart emoji\n submitBtn.title = options.label ?? 'Add to Cart';\n } else {\n submitBtn.textContent = options.label ?? 'Add to Cart';\n }\n\n function updateButtons(): void {\n decBtn.disabled = quantity <= min;\n incBtn.disabled = quantity >= max;\n }\n\n decBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (quantity > min) {\n quantity--;\n valueEl.textContent = String(quantity);\n updateButtons();\n }\n });\n\n incBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (quantity < max) {\n quantity++;\n valueEl.textContent = String(quantity);\n updateButtons();\n }\n });\n\n submitBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n options.onSubmit(quantity);\n // Brief visual feedback: show checkmark then revert\n const original = submitBtn.textContent;\n submitBtn.textContent = '\\u2713'; // checkmark\n submitBtn.classList.add('gengage-qty-submit--success');\n submitBtn.disabled = true;\n setTimeout(() => {\n submitBtn.textContent = original;\n submitBtn.classList.remove('gengage-qty-submit--success');\n submitBtn.disabled = false;\n }, 1200);\n });\n\n // Prevent card click when interacting with stepper\n container.addEventListener('click', (e) => {\n e.stopPropagation();\n });\n\n updateButtons();\n\n container.appendChild(decBtn);\n container.appendChild(valueEl);\n container.appendChild(incBtn);\n container.appendChild(submitBtn);\n\n return container;\n}\n"],"names":["TURKISH_DEFAULTS","formatPrice","raw","config","num","resolved","fixed","dotIdx","intPart","decPart","withSeparators","formatted","clampRating","value","clampDiscount","renderStarRating","rating","halfStars","clamped","full","half","empty","rounded","addImageErrorHandler","img","createQuantityStepper","options","rawMin","rawMax","min","max","initial","compact","quantity","container","decBtn","valueEl","incBtn","submitBtn","updateButtons","e","original"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";const y={currencySymbol:"TL",currencyPosition:"suffix",thousandsSeparator:".",decimalSeparator:",",alwaysShowDecimals:!1};function x(t,p){const r=Number(t);if(!Number.isFinite(r)||r<0)return t;const e={...y,...p},o=r%1!==0||e.alwaysShowDecimals?r.toFixed(2):r.toFixed(0),l=o.indexOf("."),c=l===-1?o:o.slice(0,l),i=l===-1?void 0:o.slice(l+1),s=c.replace(/\B(?=(\d{3})+(?!\d))/g,e.thousandsSeparator);let a;return i!==void 0?a=`${s}${e.decimalSeparator}${i}`:a=s,e.currencySymbol?e.currencyPosition==="prefix"?`${e.currencySymbol}${a}`:`${a} ${e.currencySymbol}`:a}function g(t){return Number.isFinite(t)?Math.max(0,Math.min(5,t)):0}function h(t){return Number.isFinite(t)?Math.max(0,Math.min(100,Math.round(t))):0}function S(t,p=!0){const r=g(t);if(p){const d=Math.floor(r),o=r-d>=.5?1:0,l=5-d-o;return"★".repeat(d)+(o?"½":"")+"☆".repeat(l)}const e=Math.round(r);return"★".repeat(e)+"☆".repeat(5-e)}function C(t){t.addEventListener("error",()=>{t.style.display="none"},{once:!0})}function E(t){const p=t.min??1,r=t.max??99,e=Math.min(p,r),d=Math.max(p,r),o=Math.max(e,Math.min(d,t.initial??e)),l=t.compact??!1;let c=o;const i=document.createElement("div");i.className=`gengage-qty-stepper${l?" gengage-qty-stepper--compact":""}`;const s=document.createElement("button");s.className="gengage-qty-btn",s.type="button",s.textContent=t.decreaseSymbol??"−",s.setAttribute("aria-label",t.decreaseLabel??"Decrease");const a=document.createElement("span");a.className="gengage-qty-value",a.textContent=String(c),a.setAttribute("aria-live","polite"),a.setAttribute("aria-atomic","true");const u=document.createElement("button");u.className="gengage-qty-btn",u.type="button",u.textContent=t.increaseSymbol??"+",u.setAttribute("aria-label",t.increaseLabel??"Increase");const n=document.createElement("button");n.className="gengage-qty-submit",n.type="button",l?(n.textContent=t.submitIcon??"🛒",n.title=t.label??"Add to Cart"):n.textContent=t.label??"Add to Cart";function b(){s.disabled=c<=e,u.disabled=c>=d}return s.addEventListener("click",m=>{m.stopPropagation(),c>e&&(c--,a.textContent=String(c),b())}),u.addEventListener("click",m=>{m.stopPropagation(),c<d&&(c++,a.textContent=String(c),b())}),n.addEventListener("click",m=>{m.stopPropagation(),t.onSubmit(c);const f=n.textContent;n.textContent="✓",n.classList.add("gengage-qty-submit--success"),n.disabled=!0,setTimeout(()=>{n.textContent=f,n.classList.remove("gengage-qty-submit--success"),n.disabled=!1},1200)}),i.addEventListener("click",m=>{m.stopPropagation()}),b(),i.appendChild(s),i.appendChild(a),i.appendChild(u),i.appendChild(n),i}exports.addImageErrorHandler=C;exports.clampDiscount=h;exports.clampRating=g;exports.createQuantityStepper=E;exports.formatPrice=x;exports.renderStarRating=S;
2
- //# sourceMappingURL=quantity-stepper-CURMkwRF.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"quantity-stepper-CURMkwRF.cjs","sources":["../src/common/price-formatter.ts","../src/common/product-utils.ts","../src/common/quantity-stepper.ts"],"sourcesContent":["/**\n * Configurable price formatting.\n *\n * Defaults to Turkish locale (dot thousands, comma decimal, TL suffix).\n * Configure via widget config `pricing` field for any locale/currency.\n */\n\nexport interface PriceFormatConfig {\n /** Currency symbol. Default: 'TL' */\n currencySymbol?: string;\n /** Where to place the symbol. Default: 'suffix' */\n currencyPosition?: 'prefix' | 'suffix';\n /** Separator between thousands. Default: '.' (Turkish) */\n thousandsSeparator?: string;\n /** Decimal point character. Default: ',' (Turkish) */\n decimalSeparator?: string;\n /** Whether to show decimal part for whole numbers. Default: false */\n alwaysShowDecimals?: boolean;\n}\n\nconst TURKISH_DEFAULTS: Required<PriceFormatConfig> = {\n currencySymbol: 'TL',\n currencyPosition: 'suffix',\n thousandsSeparator: '.',\n decimalSeparator: ',',\n alwaysShowDecimals: false,\n};\n\n/**\n * Formats a raw numeric price string into the configured locale format.\n *\n * Examples (default Turkish):\n * \"17990\" → \"17.990 TL\"\n * \"17990.5\" → \"17.990,50 TL\"\n *\n * Examples (GBP prefix):\n * \"17990\" with { currencySymbol: '£', currencyPosition: 'prefix', thousandsSeparator: ',', decimalSeparator: '.' }\n * → \"£17,990\"\n *\n * Returns the input as-is if it's not a valid number.\n */\nexport function formatPrice(raw: string, config?: PriceFormatConfig): string {\n const num = Number(raw);\n if (!Number.isFinite(num) || num < 0) return raw;\n\n const resolved = { ...TURKISH_DEFAULTS, ...config };\n\n const hasDecimals = num % 1 !== 0;\n const fixed = hasDecimals || resolved.alwaysShowDecimals ? num.toFixed(2) : num.toFixed(0);\n const dotIdx = fixed.indexOf('.');\n const intPart = dotIdx === -1 ? fixed : fixed.slice(0, dotIdx);\n const decPart = dotIdx === -1 ? undefined : fixed.slice(dotIdx + 1);\n\n // Add thousands separators to integer part\n const withSeparators = intPart.replace(/\\B(?=(\\d{3})+(?!\\d))/g, resolved.thousandsSeparator);\n\n let formatted: string;\n if (decPart !== undefined) {\n formatted = `${withSeparators}${resolved.decimalSeparator}${decPart}`;\n } else {\n formatted = withSeparators;\n }\n\n if (resolved.currencySymbol) {\n if (resolved.currencyPosition === 'prefix') {\n return `${resolved.currencySymbol}${formatted}`;\n }\n return `${formatted} ${resolved.currencySymbol}`;\n }\n\n return formatted;\n}\n","/**\n * Shared product rendering utilities.\n *\n * Extracted from chat/renderUISpec and simrel/ProductCard to eliminate\n * duplication and provide consistent behavior across all widgets.\n */\n\n/** Clamp a rating value to the 0–5 range. Returns 0 for NaN/non-finite. */\nexport function clampRating(value: number): number {\n if (!Number.isFinite(value)) return 0;\n return Math.max(0, Math.min(5, value));\n}\n\n/** Clamp a discount percentage to the 0–100 range, rounded to integer. Returns 0 for NaN/non-finite. */\nexport function clampDiscount(value: number): number {\n if (!Number.isFinite(value)) return 0;\n return Math.max(0, Math.min(100, Math.round(value)));\n}\n\n/**\n * Render a star rating string with full, half, and empty stars.\n *\n * @param rating - A numeric rating (will be clamped to 0–5).\n * @param halfStars - Whether to render half-star characters. Defaults to true.\n * @returns A string like \"★★★½☆\" or \"★★★☆☆\" (without half-stars).\n */\nexport function renderStarRating(rating: number, halfStars: boolean = true): string {\n const clamped = clampRating(rating);\n if (halfStars) {\n const full = Math.floor(clamped);\n const half = clamped - full >= 0.5 ? 1 : 0;\n const empty = 5 - full - half;\n return '\\u2605'.repeat(full) + (half ? '\\u00BD' : '') + '\\u2606'.repeat(empty);\n }\n const rounded = Math.round(clamped);\n return '\\u2605'.repeat(rounded) + '\\u2606'.repeat(5 - rounded);\n}\n\n/**\n * Attach a one-time error handler that hides the image on load failure.\n *\n * Works with any HTMLImageElement. Hides the element by setting\n * `display: none` so layout doesn't break from broken images.\n */\nexport function addImageErrorHandler(img: HTMLImageElement): void {\n img.addEventListener(\n 'error',\n () => {\n img.style.display = 'none';\n },\n { once: true },\n );\n}\n","export interface QuantityStepperOptions {\n min?: number | undefined;\n max?: number | undefined;\n initial?: number | undefined;\n label?: string | undefined;\n compact?: boolean | undefined;\n decreaseLabel?: string | undefined;\n increaseLabel?: string | undefined;\n /** Symbol for decrease button (default: '\\u2212' minus sign). */\n decreaseSymbol?: string | undefined;\n /** Symbol for increase button (default: '+'). */\n increaseSymbol?: string | undefined;\n /** Icon/text for compact mode submit button (default: shopping cart emoji). */\n submitIcon?: string | undefined;\n onSubmit: (quantity: number) => void;\n}\n\n/**\n * Creates a quantity stepper with [−] [value] [+] and a submit button.\n * Compact mode renders a cart icon button; full mode renders a labeled button.\n */\nexport function createQuantityStepper(options: QuantityStepperOptions): HTMLElement {\n const rawMin = options.min ?? 1;\n const rawMax = options.max ?? 99;\n // Ensure min <= max; swap if caller provided inverted range\n const min = Math.min(rawMin, rawMax);\n const max = Math.max(rawMin, rawMax);\n const initial = Math.max(min, Math.min(max, options.initial ?? min));\n const compact = options.compact ?? false;\n\n let quantity = initial;\n\n const container = document.createElement('div');\n container.className = `gengage-qty-stepper${compact ? ' gengage-qty-stepper--compact' : ''}`;\n\n const decBtn = document.createElement('button');\n decBtn.className = 'gengage-qty-btn';\n decBtn.type = 'button';\n decBtn.textContent = options.decreaseSymbol ?? '\\u2212'; // minus sign\n decBtn.setAttribute('aria-label', options.decreaseLabel ?? 'Decrease');\n\n const valueEl = document.createElement('span');\n valueEl.className = 'gengage-qty-value';\n valueEl.textContent = String(quantity);\n valueEl.setAttribute('aria-live', 'polite');\n valueEl.setAttribute('aria-atomic', 'true');\n\n const incBtn = document.createElement('button');\n incBtn.className = 'gengage-qty-btn';\n incBtn.type = 'button';\n incBtn.textContent = options.increaseSymbol ?? '+';\n incBtn.setAttribute('aria-label', options.increaseLabel ?? 'Increase');\n\n const submitBtn = document.createElement('button');\n submitBtn.className = 'gengage-qty-submit';\n submitBtn.type = 'button';\n\n if (compact) {\n submitBtn.textContent = options.submitIcon ?? '\\uD83D\\uDED2'; // shopping cart emoji\n submitBtn.title = options.label ?? 'Add to Cart';\n } else {\n submitBtn.textContent = options.label ?? 'Add to Cart';\n }\n\n function updateButtons(): void {\n decBtn.disabled = quantity <= min;\n incBtn.disabled = quantity >= max;\n }\n\n decBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (quantity > min) {\n quantity--;\n valueEl.textContent = String(quantity);\n updateButtons();\n }\n });\n\n incBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n if (quantity < max) {\n quantity++;\n valueEl.textContent = String(quantity);\n updateButtons();\n }\n });\n\n submitBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n options.onSubmit(quantity);\n // Brief visual feedback: show checkmark then revert\n const original = submitBtn.textContent;\n submitBtn.textContent = '\\u2713'; // checkmark\n submitBtn.classList.add('gengage-qty-submit--success');\n submitBtn.disabled = true;\n setTimeout(() => {\n submitBtn.textContent = original;\n submitBtn.classList.remove('gengage-qty-submit--success');\n submitBtn.disabled = false;\n }, 1200);\n });\n\n // Prevent card click when interacting with stepper\n container.addEventListener('click', (e) => {\n e.stopPropagation();\n });\n\n updateButtons();\n\n container.appendChild(decBtn);\n container.appendChild(valueEl);\n container.appendChild(incBtn);\n container.appendChild(submitBtn);\n\n return container;\n}\n"],"names":["TURKISH_DEFAULTS","formatPrice","raw","config","num","resolved","fixed","dotIdx","intPart","decPart","withSeparators","formatted","clampRating","value","clampDiscount","renderStarRating","rating","halfStars","clamped","full","half","empty","rounded","addImageErrorHandler","img","createQuantityStepper","options","rawMin","rawMax","min","max","initial","compact","quantity","container","decBtn","valueEl","incBtn","submitBtn","updateButtons","e","original"],"mappings":"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"}