UNPKG

vipros-sdk

Version:

VIPros SDK - Universal Web Components for cashback & VIPoints. Works with any framework!

2 lines 54.5 kB
/*! VIPros SDK v1.0.0 */ var ViprosSDK=function(){"use strict";class e{constructor(e=!1){this.debug=e,this.templates=new Map,this.baseUrl=this.detectBaseUrl()}detectBaseUrl(){const e=window.location.origin;return window.location.hostname.includes("ddev.site"),e+"/api/sdk/components/templates"}async loadTemplate(e){if(this.templates.has(e))return this.templates.get(e);try{const t=await fetch(`${this.baseUrl}/${e}.html`);if(!t.ok)throw new Error(`Template ${e} not found: ${t.status}`);const s=await t.text();return this.templates.set(e,s),s}catch(t){return this.getFallbackTemplate(e)}}async render(e,t={}){const s=await this.loadTemplate(e);return this.interpolate(s,t)}interpolate(e,t){let s=this.processConditionalBlocks(e,t);return s=s.replace(/\{\{([^}#/][^}]*)\}\}/g,(e,s)=>{const i=this.resolveNestedKey(t,s.trim());return null!==i?i:""}),s}resolveNestedKey(e,t){return t.startsWith("#")||t.startsWith("/")?"":t.split(".").reduce((e,t)=>e&&void 0!==e[t]?e[t]:null,e)}processConditionalBlocks(e,t){let s=e,i=0;for(;(s.includes("{{#if")||s.includes("{{#unless"))&&(i++,!(i>10));){const e=s;if(s=this.processIfBlocks(s,t),s=this.processUnlessBlocks(s,t),s===e)break}return s}processIfBlocks(e,t){return e.replace(/\{\{#if\s+([^}]+)\}\}((?:(?!\{\{#if)[\s\S])*?)\{\{\/if\}\}/g,(e,s,i)=>{const r=this.resolveNestedKey(t,s.trim()),n=Boolean(r),a=i.split(/\{\{else\}\}/);return 2===a.length?n?a[0]:a[1]:n?i:""})}processUnlessBlocks(e,t){return e.replace(/\{\{#unless\s+([^}]+)\}\}((?:(?!\{\{#unless)[\s\S])*?)\{\{\/unless\}\}/g,(e,s,i)=>{const r=this.resolveNestedKey(t,s.trim());return!Boolean(r)?i:""})}handleConditional(e,t,s){const i=t.split(" ")[1],r=this.resolveNestedKey(e,i),n=Boolean(r);return(s?n:!n)?"":"\x3c!-- condition-false --\x3e"}getFallbackTemplate(e){return{CashbackTemplate:'\n <div class="vipros-offer-card cashback-mode">\n <div class="offer-content">\n <div class="main-value">\n <span class="amount">{{cashback.value}}</span>\n <span class="currency">€</span>\n <span class="label">remboursés</span>\n </div>\n </div>\n </div>\n ',VIPointsTemplate:'\n <div class="vipros-offer-card vipoints-mode">\n <div class="offer-content">\n <div class="main-value">\n <span class="amount">{{vipoints.perTenEuros}}</span>\n <span class="label">VIPoints</span>\n </div>\n </div>\n </div>\n ',LoadingTemplate:'\n <div class="vipros-offer-card loading-state">\n <div class="loading-text">Recherche...</div>\n </div>\n ',ErrorTemplate:'\n <div class="vipros-offer-card error-state">\n <div class="error-text">{{message}}</div>\n <div class="debug-notice">Erreur affichée car le mode debug est activé</div>\n </div>\n '}[e]||'<div class="vipros-offer-card">Template not found</div>'}async preloadTemplates(){const e=["CashbackTemplate","VIPointsTemplate","LoadingTemplate","ErrorTemplate"].map(e=>this.loadTemplate(e).catch(e=>(this.debug,null)));await Promise.all(e),this.debug}clearCache(){this.templates.clear()}}class t{static transform(e,t=null){if(!e)return null;const s=Boolean(e.cashback?.value>0),i=e.brand?.generosity_rate||0,r=this.calculateVIPoints(i,t);return{id:e.id||"not_found",ean:e.ean,name:e.name||"Produit inconnu",price:t,brand:this.transformBrandData(e.brand),cashback:this.transformCashbackData(e.cashback),vipoints:r,hasCashback:s,viprosLink:this.buildViprosLink(e),vipointsImageUrl:null}}static transformBrandData(e){if(!e)return{name:"Marque inconnue",displayName:null,logoUrl:null,generosityRate:0};const t=e.name&&"Marque inconnue"!==e.name?e.name:null;return{name:e.name||"Marque inconnue",displayName:t,logoUrl:e.logo_url||null,generosityRate:e.generosity_rate||0}}static transformCashbackData(e){return e?{value:e.value||0,name:e.name||null,imageUrl:e.image_url||null,startDate:e.start_date||null,endDate:e.end_date||null}:{value:0,name:null,imageUrl:null,startDate:null,endDate:null}}static calculateVIPoints(e,t){let s=0,i=!1,r=!1;return e>0&&(i=!0,t&&t>0?(s=Math.floor(e*t/10),r=!0):(s=1,r=!1)),{perTenEuros:s,generosityRate:e,hasBonus:i,showExact:r}}static determineDisplayMode(e){return e?e.hasCashback?"cashback":e.vipoints.hasBonus?"vipoints":"empty":"empty"}static validate(e){if(!e)return{isValid:!1,errors:["No data provided"]};const t=[];return e.ean||t.push("EAN is required"),e.hasCashback&&!e.cashback.value&&t.push("Cashback value is required when hasCashback is true"),e.vipoints.hasBonus&&!e.vipoints.generosityRate&&t.push("Generosity rate is required when VIPoints bonus is available"),{isValid:0===t.length,errors:t}}static prepareTemplateData(e,t=null){return e?{...e,vipointsImageUrl:t||this.getDefaultVIPointsImageUrl()}:null}static buildViprosLink(e){const t=e.vipros_link||"https://vipros.fr",s=this.getSalesPointName(e),i="undefined"!=typeof window?window.location.href:"",r=new URL(t);return s&&r.searchParams.set("origin",s),i&&r.searchParams.set("origin_url",i),r.toString()}static getSalesPointName(e){if(e.sales_points&&Array.isArray(e.sales_points)){const t=e.sales_points.find(e=>e.name);if(t)return t.name}if("undefined"!=typeof window){return window.location.hostname.replace(/^www\./,"").replace(/\./g," ").split(" ")[0]}return null}static getDefaultVIPointsImageUrl(){return"/api/sdk/assets/image-vipoints.jpg"}}class s{static resolveDisplayMode(e){return e?e.hasCashback?"cashback":e.vipoints.hasBonus?"vipoints":"empty":"empty"}static resolveTemplateName(e){return{cashback:"CashbackTemplate",vipoints:"VIPointsTemplate",loading:"LoadingTemplate",error:"ErrorTemplate",empty:null,hidden:null}[e]||null}static shouldDisplay(e){return!["empty","hidden"].includes(e)}static resolveContainerClass(e){return`vipros-offer-card ${{cashback:"cashback-mode",vipoints:"vipoints-mode",loading:"loading-state",error:"error-state",empty:"empty-state",hidden:"hidden-state"}[e]||""}`}static validateDisplayMode(e){return["cashback","vipoints","loading","error","empty","hidden"].includes(e)?e:"error"}static analyze(e,t={}){const{isLoading:s=!1,error:i=null,debug:r=!1}=t;if(i)return r?{mode:"error",template:"ErrorTemplate",shouldDisplay:!0,containerClass:this.resolveContainerClass("error"),data:{message:i.message||"Une erreur est survenue",debugMode:!0}}:{mode:"hidden",template:null,shouldDisplay:!1,containerClass:this.resolveContainerClass("hidden"),data:{}};if(s)return{mode:"loading",template:"LoadingTemplate",shouldDisplay:!0,containerClass:this.resolveContainerClass("loading"),data:{}};const n=this.resolveDisplayMode(e),a=this.resolveTemplateName(n),o=this.shouldDisplay(n),c=this.resolveContainerClass(n);return{mode:this.validateDisplayMode(n),template:a,shouldDisplay:o,containerClass:c,data:o?e:{}}}static hasMinimumRequiredData(e){return!!e&&(!!e.ean&&(e.hasCashback||e.vipoints.hasBonus))}static suggestDataImprovements(e){if(!e)return["Product data is required"];const t=[];return e.name&&"Produit inconnu"!==e.name||t.push("Product name could be improved"),e.hasCashback&&!e.cashback.imageUrl&&t.push("Cashback image would improve visual appeal"),!e.price&&e.vipoints.hasBonus&&t.push("Price would enable exact VIPoints calculation"),e.brand.displayName||t.push("Brand name would improve VIPoints messaging"),t}}class i{constructor(e){this.element=e,this.listeners=new Map}emit(e,t={}){const s=new CustomEvent(e,{detail:t,bubbles:!0,cancelable:!0});this.element.dispatchEvent(s),this.element.getAttribute("debug")}emitOfferLoaded(e,t){this.emit("vipros-offer-loaded",{product:e,ean:t,timestamp:Date.now()})}emitError(e,t){this.emit("vipros-offer-error",{error:{message:e.message||"Unknown error",type:e.constructor.name,stack:e.stack},ean:t,timestamp:Date.now()})}emitOfferClick(e,t,s){this.emit("vipros-offer-click",{url:e,product:t,ean:s,timestamp:Date.now()})}emitSyncStarted(e,t){this.emit("vipros-sync-started",{ean:e,url:t,timestamp:Date.now()})}emitSyncSuccess(e,t){this.emit("vipros-sync-success",{ean:e,result:t,timestamp:Date.now()})}emitSyncError(e,t){this.emit("vipros-sync-error",{ean:e,error:{message:t.message||"Sync error",type:t.constructor.name},timestamp:Date.now()})}attachLinkListeners(e,t,s){e.querySelectorAll("a[href]").forEach(e=>{const i=i=>{this.emitOfferClick(e.href,t,s),window.gtag&&window.gtag("event","vipros_offer_click",{ean:s,url:e.href,product_name:t?.name})};e.addEventListener("click",i),this.listeners.has("linkClicks")||this.listeners.set("linkClicks",[]),this.listeners.get("linkClicks").push({link:e,handler:i})})}cleanup(){this.listeners.has("linkClicks")&&this.listeners.get("linkClicks").forEach(({link:e,handler:t})=>{e.removeEventListener("click",t)}),this.listeners.clear()}enableGlobalDebugging(){["vipros-offer-loaded","vipros-offer-error","vipros-offer-click","vipros-sync-started","vipros-sync-success","vipros-sync-error"].forEach(e=>{document.addEventListener(e,e=>{})})}static emit(e,t,s={}){new i(e).emit(t,s)}static emitOfferLoaded(e,t,s){new i(e).emitOfferLoaded(t,s)}static emitError(e,t,s){new i(e).emitError(t,s)}}class r extends HTMLElement{constructor(){super(),this.attachShadow({mode:"open"}),this.templateLoader=new e,this.eventManager=new i(this),this.state={isLoading:!1,productData:null,error:null,apiClient:null},this.init=this.init.bind(this),this.loadProduct=this.loadProduct.bind(this),this.render=this.render.bind(this)}static get observedAttributes(){return["ean","price","api-base-url","api-key","primary-color","text-color","background-color","card-bonus-bg","card-bonus-color"]}get ean(){return this.getAttribute("ean")||this.getConfigValue("ean")}get price(){const e=parseFloat(this.getAttribute("price"))||0;if(e>0)return e;const t=this.getConfigValue("price");return t&&parseFloat(t)>0?parseFloat(t):null}get apiBaseUrl(){return this.getConfigValue("apiBaseUrl")||this.getAttribute("api-base-url")||this.detectFallbackApiBaseUrl()}get apiKey(){return this.getConfigValue("apiKey")||this.getAttribute("api-key")}get primaryColor(){return this.getAttribute("primary-color")||this.getConfigValue("primaryColor")}get textColor(){return this.getAttribute("text-color")||this.getConfigValue("textColor")}get backgroundColor(){return this.getAttribute("background-color")||this.getConfigValue("backgroundColor")}get cardBonusBg(){return this.getAttribute("card-bonus-bg")||this.getConfigValue("cardBonusBg")}get cardBonusColor(){return this.getAttribute("card-bonus-color")||this.getConfigValue("cardBonusColor")}getConfigValue(e){const t=this.getSDKInstance();return t?.config?.[e]||null}getSDKInstance(){return"undefined"!=typeof window?window.ViprosSDK:null}detectFallbackApiBaseUrl(){if("undefined"==typeof window)return this.log("[ViprosOfferCard] No window object - defaulting to production API"),"https://msys.vipros.fr/api";try{if(!window.location||"string"!=typeof window.location.hostname)return this.log("[ViprosOfferCard] Invalid window.location - defaulting to production API"),"https://msys.vipros.fr/api";const e=window.location.protocol||"https:",t=window.location.hostname.toLowerCase();return t&&0!==t.length?"file:"===e||"localhost"===t||t.startsWith("127.0.0.1")||t.startsWith("0.0.0.0")?(this.log("[ViprosOfferCard] Local development detected - using DDEV fallback"),"https://vipros-connect.ddev.site/api"):"vipros-connect.ddev.site"===t?`${e}//${t}/api`:"msys.preprod.vipros.fr"===t?`${e}//msys.preprod.vipros.fr/api`:t.endsWith(".vipros.fr")?(this.log(`[ViprosOfferCard] VIPros subdomain detected: ${t}`),`${e}//${t}/api`):(this.log(`[ViprosOfferCard] Unknown domain: ${t} - defaulting to production API`),"https://msys.vipros.fr/api"):(this.log("[ViprosOfferCard] Empty hostname - defaulting to production API"),"https://msys.vipros.fr/api")}catch(e){return this.log(`[ViprosOfferCard] Error detecting API base URL: ${e.message} - defaulting to production`),"https://msys.vipros.fr/api"}}connectedCallback(){this.log("[ViprosOfferCard] Component connected"),this.init()}attributeChangedCallback(e,t,s){t!==s&&this.isConnected&&("ean"===e?(this.log(`[ViprosOfferCard] EAN changed: ${t} → ${s}`),this.loadProduct()):["primary-color","text-color","background-color","gift-icon-color","gift-card-bonus-bg","gift-card-bonus-color","vipoints-bonus-bg","vipoints-bonus-color"].includes(e)&&(this.log(`[ViprosOfferCard] Color changed: ${e} = ${s}`),this.updateCustomColors()))}disconnectedCallback(){this.log("[ViprosOfferCard] Component disconnected"),this.cleanup()}async init(){try{this.loadGoogleFonts(),await this.loadStyles(),this.updateCustomColors(),await this.initApiClient(),await this.templateLoader.preloadTemplates(),this.ean?await this.loadProduct():this.setError(new Error("EAN requis pour afficher une offre VIPros"))}catch(e){this.logError("[ViprosOfferCard] Init error:",e),this.setError(e)}}loadGoogleFonts(){["https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;500;600;700&display=swap","https://fonts.googleapis.com/css2?family=Encode+Sans+Condensed:wght@100;200;300;400;500;600;700;800;900&display=swap"].forEach(e=>{if(!document.querySelector(`link[href="${e}"]`)){const t=document.createElement("link");t.rel="stylesheet",t.href=e,t.crossOrigin="anonymous",document.head.appendChild(t)}})}async loadStyles(){try{const e=this.templateLoader.baseUrl.replace("/components/templates","/components/styles/offer-card.css"),t=await fetch(e);if(t.ok){const e=await t.text(),s=document.createElement("style");s.textContent=e,this.shadowRoot.appendChild(s)}else this.injectFallbackStyles()}catch(e){this.logError("[ViprosOfferCard] CSS loading failed, using fallback"),this.injectFallbackStyles()}}updateCustomColors(){if(!this.shadowRoot)return;const e=this.shadowRoot.host,t={};this.primaryColor&&(t["--vipros-primary"]=this.primaryColor,t["--vipros-text-accent"]=this.primaryColor),this.textColor&&(t["--vipros-text-main"]=this.textColor),this.backgroundColor&&(t["--vipros-background"]=this.backgroundColor),this.cardBonusBg&&(t["--card-bonus-bg"]=this.cardBonusBg),this.cardBonusColor&&(t["--card-bonus-color"]=this.cardBonusColor),Object.entries(t).forEach(([t,s])=>{e.style.setProperty(t,s)}),this.log("[ViprosOfferCard] Custom colors applied:",t)}injectFallbackStyles(){const e=document.createElement("style");e.textContent="\n .vipros-offer-card { \n display: block; \n padding: 20px; \n background: #e8ecf8; \n border-radius: 12px; \n font-family: sans-serif; \n }\n .loading-content, .error-content { \n text-align: center; \n padding: 40px; \n }\n ",this.shadowRoot.appendChild(e)}log(e,...t){const s=this.getSDKInstance();s&&s.config&&s.config.debug}logError(e,...t){const s=this.getSDKInstance();s&&s.config&&s.config.debug}async initApiClient(){const e=this.getSDKInstance();if(e&&e.getApiClient)this.state.apiClient=e.getApiClient(),this.log("[ViprosOfferCard] Using shared SDK ApiClient");else{const{default:e}=await Promise.resolve().then(function(){return N});this.state.apiClient=new e({apiBaseUrl:this.apiBaseUrl,apiKey:this.apiKey}),this.log("[ViprosOfferCard] Created local ApiClient")}}async loadProduct(){if(this.ean&&!this.state.isLoading)if(this.state.apiClient){this.setLoading(!0);try{this.log(`[ViprosOfferCard] Loading product: ${this.ean}`);const e=this.getSDKInstance(),s={timeout:5e3};e?.config?.inlineSyncEnabled&&(s.enableInlineSync=!0,s.productUrl=window.location.href,this.log(`[ViprosOfferCard] Inline sync enabled for EAN ${this.ean}`));const i=await this.state.apiClient.get("/catalog/items",{ean:this.ean,items_per_page:1},s),r=i?.metadata?.bloomFilter,n=Boolean(this.getConfigValue("debug")||"true"===this.getAttribute("debug"));if(r?.skipped){if(this.log(`[ViprosOfferCard] Bloom filter skipped API call for EAN ${this.ean}`),n){const e=new Error("404 | Produit introuvable (Bloom filter)");e.status=404,e.type="BLOOM_FILTER_NOT_FOUND",e.data={ean:this.ean,reason:r.reason||"NOT_IN_FILTER"},this.setError(e)}else this.setProductData(null);return}const a=i?.sdk_metadata?.sync;if(a&&this.getConfigValue("debug")&&this.log("[ViprosOfferCard] Sync metadata:",a),i.items&&i.items.length>0){const e=t.transform(i.items[0],this.price);e.vipointsImageUrl=this.getVIPointsImageUrl(),this.setProductData(e),this.log(`[ViprosOfferCard] Product loaded: ${e.name}`);null!=a?this.log(`[ViprosOfferCard] Skipping background sync (inline sync was attempted, status: ${a.reason||"unknown"})`):this.triggerBackgroundSync(),this.eventManager.emitOfferLoaded(e,this.ean)}else this.log(`[ViprosOfferCard] No product found for EAN: ${this.ean}`),this.setProductData(null)}catch(e){if(this.logError(`[ViprosOfferCard] Error loading EAN ${this.ean}:`,e),429===e.status||"RATE_LIMIT_ERROR"===e.type){const e=new Error("API rate limit exceeded - Trop de requêtes simultanées");e.status=429,e.type="RATE_LIMIT_ERROR",this.setError(e)}else this.setError(e)}finally{this.setLoading(!1)}}else setTimeout(()=>this.loadProduct(),100)}setLoading(e){this.state.isLoading=e,this.render()}setProductData(e){this.state.productData=e,this.state.error=null}setError(e){this.state.error=e,this.state.productData=null,this.render(),this.eventManager.emitError(e,this.ean)}async render(){const e=s.analyze(this.state.productData,{isLoading:this.state.isLoading,error:this.state.error,debug:this.getConfigValue("debug")||!1});if(e.shouldDisplay){if(e.template){const t=await this.templateLoader.render(e.template,e.data);this.updateShadowContent(t),this.state.isLoading||this.attachEventListeners()}}else this.updateShadowContent('<div class="vipros-offer-card hidden"></div>')}async renderLoading(){await this.render()}updateShadowContent(e){const t=Array.from(this.shadowRoot.querySelectorAll("style")).map(e=>e.textContent);this.shadowRoot.replaceChildren();const s=document.createElement("div");for(s.innerHTML=e;s.firstChild;)this.shadowRoot.appendChild(s.firstChild);t.forEach(e=>{const t=document.createElement("style");t.textContent=e,this.shadowRoot.appendChild(t)})}attachEventListeners(){this.state.productData&&this.eventManager.attachLinkListeners(this.shadowRoot,this.state.productData,this.ean)}getVIPointsImageUrl(){return`${(this.apiBaseUrl||"").replace("/api","")}/api/sdk/assets/image-vipoints.jpg`}triggerBackgroundSync(){const e=this.getSDKInstance();e?.syncService&&setTimeout(()=>{this.log(`[ViprosOfferCard] Background sync for EAN ${this.ean}`),e.syncProductInBackground(this.ean,window.location.href)},100)}cleanup(){this.eventManager.cleanup(),this.state.apiClient=null,this.state.productData=null}}r.setSDKInstance=function(e){};class n{static create(e={}){const t=n.getDefaultConfig(),s=n.mergeConfig(t,e);return n.validateConfig(s)}static getDefaultConfig(){return{apiBaseUrl:n.detectApiBaseUrl(),apiKey:null,timeout:1e4,ean:null,price:null,primaryColor:null,textColor:null,backgroundColor:null,cardBonusBg:null,cardBonusColor:null,cacheTimeout:3e5,cachePrefix:"vipros_sdk_",maxCacheSize:100,containerSelector:"[data-ean]",eanAttribute:"data-ean",renderPosition:"replace",excludeSelectors:[".vipros-offer","[data-vipros-exclude]"],templates:{},styling:{theme:"minimal",customCSS:{},inlineStyles:!0,cssPrefix:"vipros-",responsive:!0},batchRequests:!0,lazyLoad:!0,maxConcurrentRequests:3,debounceDelay:300,hideOnError:!1,retryOnError:!0,gracefulDegradetion:!0,syncEnabled:!0,syncOptions:{cooldownTime:864e5,syncDelay:100,maxRetries:3,retryDelay:1e3},debug:!1,verbose:!1,logLevel:"warn",onReady:null,onOfferFound:null,onOfferRendered:null,onOfferLoaded:null,onError:null,features:{analyticsTracking:!1,performanceMonitoring:!1,a11yEnhancements:!0,seoOptimizations:!0},locale:"fr-FR",currency:"EUR",dateFormat:"DD/MM/YYYY",version:"1.0.0"}}static mergeConfig(e,t){return n.deepMerge(e,t)}static deepMerge(e,t){const s={...e};for(const[e,i]of Object.entries(t))null!=i&&(n.isObject(i)&&n.isObject(s[e])?s[e]=n.deepMerge(s[e],i):s[e]=i);return s}static isObject(e){return e&&"object"==typeof e&&!Array.isArray(e)}static validateConfig(e){const t=[];if(e.apiBaseUrl&&"string"==typeof e.apiBaseUrl)try{new URL(e.apiBaseUrl)}catch(e){t.push("apiBaseUrl must be a valid URL")}else t.push("apiBaseUrl must be a valid string");if(e.apiKey||t.push("apiKey is required"),e.apiKey&&"string"!=typeof e.apiKey&&t.push("apiKey must be a string"),e.timeout&&("number"!=typeof e.timeout||e.timeout<=0)&&t.push("timeout must be a positive number"),e.cacheTimeout&&("number"!=typeof e.cacheTimeout||e.cacheTimeout<0)&&t.push("cacheTimeout must be a non-negative number"),e.maxCacheSize&&("number"!=typeof e.maxCacheSize||e.maxCacheSize<=0)&&t.push("maxCacheSize must be a positive number"),e.containerSelector&&"string"!=typeof e.containerSelector&&t.push("containerSelector must be a string"),e.eanAttribute&&"string"!=typeof e.eanAttribute&&t.push("eanAttribute must be a string"),e.styling){const s=["minimal","branded","custom"];e.styling.theme&&!s.includes(e.styling.theme)&&t.push(`styling.theme must be one of: ${s.join(", ")}`),e.styling.customCSS&&!n.isObject(e.styling.customCSS)&&t.push("styling.customCSS must be an object")}e.maxConcurrentRequests&&("number"!=typeof e.maxConcurrentRequests||e.maxConcurrentRequests<=0)&&t.push("maxConcurrentRequests must be a positive number"),e.debounceDelay&&("number"!=typeof e.debounceDelay||e.debounceDelay<0)&&t.push("debounceDelay must be a non-negative number");const s=["error","warn","info","debug"];e.logLevel&&!s.includes(e.logLevel)&&t.push(`logLevel must be one of: ${s.join(", ")}`);const i=["onReady","onOfferFound","onOfferRendered","onOfferLoaded","onError"];for(const s of i)e[s]&&"function"!=typeof e[s]&&t.push(`${s} must be a function`);if(e.locale&&"string"!=typeof e.locale&&t.push("locale must be a string"),e.currency&&"string"!=typeof e.currency&&t.push("currency must be a string"),t.length>0){const e=new Error(`Configuration validation failed:\n${t.join("\n")}`);throw e.validationErrors=t,e}return n.processConfig(e)}static processConfig(e){const t={...e};if(t.apiBaseUrl=t.apiBaseUrl.replace(/\/$/,""),t.containerSelector.startsWith("[")||t.containerSelector.startsWith(".")||t.containerSelector.startsWith("#")||(t.containerSelector=`[${t.eanAttribute}]`),"debug"===t.logLevel?(t.debug=!0,t.verbose=!0):"info"===t.logLevel&&(t.debug=!0),t.styling.customCSS){const e={};for(const[s,i]of Object.entries(t.styling.customCSS)){e[s.startsWith("--")?s:`--vipros-${s}`]=i}t.styling.customCSS=e}return t.cachePrefix=`${t.cachePrefix}v${t.version.replace(/\./g,"_")}_`,t.derived={isProduction:!t.debug,shouldCache:t.cacheTimeout>0,shouldBatch:t.batchRequests&&t.maxConcurrentRequests>1,shouldLazyLoad:t.lazyLoad,hasCustomStyling:"custom"===t.styling.theme||Object.keys(t.styling.customCSS||{}).length>0},t}static createSecureConfig(e,t={}){const s={apiBaseUrl:t.apiBaseUrl,allowedFeatures:t.allowedFeatures,rateLimits:t.rateLimits,version:t.version};return n.create({...s,...e})}static validateRuntimeConfig(e){if(!e)throw new Error("Configuration is required");if(!e.derived)throw new Error("Configuration has not been processed");return!0}static getConfigSummary(e){return{version:e.version,apiBaseUrl:e.apiBaseUrl,theme:e.styling.theme,cacheEnabled:e.derived.shouldCache,debugMode:e.debug,features:Object.keys(e.features).filter(t=>e.features[t])}}static detectApiBaseUrl(e=!1){try{if("undefined"==typeof window)return"https://msys.vipros.fr/api";if(!window.location||"string"!=typeof window.location.hostname)return"https://msys.vipros.fr/api";const e=window.location.protocol||"https:",t=window.location.hostname.toLowerCase();return t&&0!==t.length?"file:"===e||"localhost"===t||t.startsWith("127.0.0.1")||t.startsWith("0.0.0.0")||t.includes(":")&&(t.includes("localhost")||t.includes("127.0.0.1"))?"https://vipros-connect.ddev.site/api":"vipros-connect.ddev.site"===t?`${e}//${t}/api`:"msys.preprod.vipros.fr"===t?`${e}//msys.preprod.vipros.fr/api`:t.endsWith(".vipros.fr")?`${e}//${t}/api`:(/^\d+\.\d+\.\d+\.\d+$/.test(t),"https://msys.vipros.fr/api"):"https://msys.vipros.fr/api"}catch(e){return"https://msys.vipros.fr/api"}}}class a{constructor(){this.events=new Map,this.maxListeners=10}on(e,t){if("function"!=typeof t)throw new TypeError("Callback must be a function");this.events.has(e)||this.events.set(e,[]);const s=this.events.get(e);return s.length,this.maxListeners,s.push(t),this}once(e,t){if("function"!=typeof t)throw new TypeError("Callback must be a function");const s=(...i)=>{this.off(e,s),t.apply(this,i)};return this.on(e,s)}off(e,t){if(!this.events.has(e))return this;if(!t)return this.events.delete(e),this;const s=this.events.get(e),i=s.indexOf(t);return-1!==i&&s.splice(i,1),0===s.length&&this.events.delete(e),this}emit(e,...t){if(!this.events.has(e))return!1;const s=this.events.get(e).slice();for(const e of s)try{e.apply(this,t)}catch(e){this.emit("error",e)}return!0}removeAllListeners(e=null){return e?this.events.delete(e):this.events.clear(),this}listenerCount(e){return this.events.has(e)?this.events.get(e).length:0}getMaxListeners(){return this.maxListeners}setMaxListeners(e){if("number"!=typeof e||e<0)throw new TypeError("Max listeners must be a non-negative number");return this.maxListeners=e,this}eventNames(){return Array.from(this.events.keys())}listeners(e){return this.events.has(e)?this.events.get(e).slice():[]}}var o=Uint8Array,c=Uint16Array,l=Int32Array,h=new o([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),u=new o([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),d=new o([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),p=function(e,t){for(var s=new c(31),i=0;i<31;++i)s[i]=t+=1<<e[i-1];var r=new l(s[30]);for(i=1;i<30;++i)for(var n=s[i];n<s[i+1];++n)r[n]=n-s[i]<<5|i;return{b:s,r:r}},m=p(h,2),g=m.b,f=m.r;g[28]=258,f[258]=28;for(var y=p(u,0).b,b=new c(32768),v=0;v<32768;++v){var C=(43690&v)>>1|(21845&v)<<1;C=(61680&(C=(52428&C)>>2|(13107&C)<<2))>>4|(3855&C)<<4,b[v]=((65280&C)>>8|(255&C)<<8)>>1}var w=function(e,t,s){for(var i=e.length,r=0,n=new c(t);r<i;++r)e[r]&&++n[e[r]-1];var a,o=new c(t);for(r=1;r<t;++r)o[r]=o[r-1]+n[r-1]<<1;if(s){a=new c(1<<t);var l=15-t;for(r=0;r<i;++r)if(e[r])for(var h=r<<4|e[r],u=t-e[r],d=o[e[r]-1]++<<u,p=d|(1<<u)-1;d<=p;++d)a[b[d]>>l]=h}else for(a=new c(i),r=0;r<i;++r)e[r]&&(a[r]=b[o[e[r]-1]++]>>15-e[r]);return a},S=new o(288);for(v=0;v<144;++v)S[v]=8;for(v=144;v<256;++v)S[v]=9;for(v=256;v<280;++v)S[v]=7;for(v=280;v<288;++v)S[v]=8;var E=new o(32);for(v=0;v<32;++v)E[v]=5;var k=w(S,9,1),L=w(E,5,1),R=function(e){for(var t=e[0],s=1;s<e.length;++s)e[s]>t&&(t=e[s]);return t},A=function(e,t,s){var i=t/8|0;return(e[i]|e[i+1]<<8)>>(7&t)&s},T=function(e,t){var s=t/8|0;return(e[s]|e[s+1]<<8|e[s+2]<<16)>>(7&t)},I=function(e){return(e+7)/8|0},D=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"],_=function(e,t,s){var i=new Error(t||D[e]);if(i.code=e,Error.captureStackTrace&&Error.captureStackTrace(i,_),!s)throw i;return i},O=function(e,t,s,i){var r=e.length;if(!r||t.f&&!t.l)return s||new o(0);var n=!s,a=n||2!=t.i,c=t.i;n&&(s=new o(3*r));var l=function(e){var t=s.length;if(e>t){var i=new o(Math.max(2*t,e));i.set(s),s=i}},p=t.f||0,m=t.p||0,f=t.b||0,b=t.l,v=t.d,C=t.m,S=t.n,E=8*r;do{if(!b){p=A(e,m,1);var D=A(e,m+1,3);if(m+=3,!D){var O=e[(M=I(m)+4)-4]|e[M-3]<<8,U=M+O;if(U>r){c&&_(0);break}a&&l(f+O),s.set(e.subarray(M,U),f),t.b=f+=O,t.p=m=8*U,t.f=p;continue}if(1==D)b=k,v=L,C=9,S=5;else if(2==D){var B=A(e,m,31)+257,$=A(e,m+10,15)+4,P=B+A(e,m+5,31)+1;m+=14;for(var V=new o(P),x=new o(19),N=0;N<$;++N)x[d[N]]=A(e,m+3*N,7);m+=3*$;var z=R(x),K=(1<<z)-1,F=w(x,z,1);for(N=0;N<P;){var M,q=F[A(e,m,K)];if(m+=15&q,(M=q>>4)<16)V[N++]=M;else{var j=0,W=0;for(16==M?(W=3+A(e,m,3),m+=2,j=V[N-1]):17==M?(W=3+A(e,m,7),m+=3):18==M&&(W=11+A(e,m,127),m+=7);W--;)V[N++]=j}}var Q=V.subarray(0,B),H=V.subarray(B);C=R(Q),S=R(H),b=w(Q,C,1),v=w(H,S,1)}else _(1);if(m>E){c&&_(0);break}}a&&l(f+131072);for(var G=(1<<C)-1,X=(1<<S)-1,J=m;;J=m){var Y=(j=b[T(e,m)&G])>>4;if((m+=15&j)>E){c&&_(0);break}if(j||_(2),Y<256)s[f++]=Y;else{if(256==Y){J=m,b=null;break}var Z=Y-254;if(Y>264){var ee=h[N=Y-257];Z=A(e,m,(1<<ee)-1)+g[N],m+=ee}var te=v[T(e,m)&X],se=te>>4;te||_(3),m+=15&te;H=y[se];if(se>3){ee=u[se];H+=T(e,m)&(1<<ee)-1,m+=ee}if(m>E){c&&_(0);break}a&&l(f+131072);var ie=f+Z;if(f<H){var re=0-H,ne=Math.min(H,ie);for(re+f<0&&_(3);f<ne;++f)s[f]=i[re+f]}for(;f<ie;++f)s[f]=s[f-H]}}t.l=b,t.p=J,t.b=f,t.f=p,b&&(p=1,t.m=C,t.d=v,t.n=S)}while(!p);return f!=s.length&&n?function(e,t,s){return(null==s||s>e.length)&&(s=e.length),new o(e.subarray(t,s))}(s,0,f):s.subarray(0,f)},U=new o(0);function B(e,t){var s,i,r=function(e){31==e[0]&&139==e[1]&&8==e[2]||_(6,"invalid gzip data");var t=e[3],s=10;4&t&&(s+=2+(e[10]|e[11]<<8));for(var i=(t>>3&1)+(t>>4&1);i>0;i-=!e[s++]);return s+(2&t)}(e);return r+8>e.length&&_(6,"invalid gzip data"),O(e.subarray(r,-8),{i:2},new o((i=(s=e).length,(s[i-4]|s[i-3]<<8|s[i-2]<<16|s[i-1]<<24)>>>0)),t)}function $(e,t){return O(e.subarray(((8!=(15&(s=e)[0])||s[0]>>4>7||(s[0]<<8|s[1])%31)&&_(6,"invalid zlib data"),1==(s[1]>>5&1)&&_(6,"invalid zlib data: "+(32&s[1]?"need":"unexpected")+" dictionary"),2+(s[1]>>3&4)),-4),{i:2},t,t);var s}var P="undefined"!=typeof TextDecoder&&new TextDecoder;try{P.decode(U,{stream:!0})}catch(e){}class V{constructor(e,t={}){this.debugEnabled=Boolean(t.debug);try{this.bits=this.decompress(e),this.size=8*this.bits.length,this.k=7}catch(t){this.bits=e,this.size=8*this.bits.length,this.k=7}}test(e){if(!this.isValidEan(e))return this.debug("[BloomFilter] Invalid EAN format:",e),!1;this.debug("[BloomFilter] Testing EAN:",e,"Size:",this.size,"Bits length:",this.bits.length);for(let t=0;t<this.k;t++){const s=this.hash(e+t),i=s%this.size,r=Math.floor(i/8),n=i%8,a=!!(this.bits[r]&1<<n);if(this.debug(`[BloomFilter] Hash ${t}: ${s} % ${this.size} = ${i}, byte=${r}, bit=${n}, value=${a}`),!a)return this.debug(`[BloomFilter] EAN ${e} NOT found (hash ${t} failed)`),!1}return this.debug(`[BloomFilter] EAN ${e} FOUND (all ${this.k} hashes passed)`),!0}hash(e){const t=this.getCrc32Table();let s=4294967295;for(let i=0;i<e.length;i++){s=s>>>8^t[255&(s^e.charCodeAt(i))]}return Math.abs((4294967295^s)>>>0)}getCrc32Table(){return this.crc32Table||(this.crc32Table=new Uint32Array([0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918e3,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117])),this.crc32Table}isValidEan(e){return"string"==typeof e&&/^\d{8}$|^\d{12}$|^\d{13}$/.test(e)}decompress(e){try{let t=e instanceof Uint8Array?e:new Uint8Array(e);if(0===t.length)return t;if(120===t[0]){this.debug("[BloomFilter] Detected zlib/gzcompress data, inflating");try{return $(t)}catch(e){this.debug("[BloomFilter] unzlibSync failed, fallback to raw:",e.message)}}if(31===t[0]&&139===t[1]){this.debug("[BloomFilter] Detected gzip data, inflating");try{return B(t)}catch(e){this.debug("[BloomFilter] gunzipSync failed, fallback to raw:",e.message)}}}catch(e){this.debug("[BloomFilter] Decompression failed:",e.message)}const t=e instanceof Uint8Array?e:new Uint8Array(e);return this.debug("[BloomFilter] Using raw data, size:",t.length),t}getStats(){return{size:this.size,bytes:this.bits.length,hashFunctions:this.k,loaded:!0}}debug(...e){this.debugEnabled}}class x extends a{constructor(e){super(),this.config=e,this.baseUrl=this.config.apiBaseUrl,this.defaultHeaders=this.buildDefaultHeaders(),this.retryConfig={maxRetries:3,baseDelay:1e3,maxDelay:1e4},this.requestQueue=[],this.isProcessingQueue=!1,this.rateLimitInfo={remaining:null,resetTime:null,limit:null},this.bloomFilter=null,this.bloomLoaded=!1,this.bloomLoadPromise=null}buildDefaultHeaders(){const e=this.config.version||"3.0.0-unified",t={"Content-Type":"application/json",Accept:"application/json","User-Agent":`ViprosSDK/${e} (JavaScript)`,"X-SDK-Version":e,"X-SDK-Client":"JavaScript"};return this.config.apiKey&&(t["x-api-key"]=this.config.apiKey),"undefined"!=typeof window&&window.location&&(t.Referer=window.location.href,t.Origin=window.location.origin),t}async getCatalogItems(e={},t={}){this.debug("[ViprosSDK] getCatalogItems() called with filters:",e,"options:",t);const s=new URLSearchParams;Object.entries(e).forEach(([e,t])=>{null!=t&&""!==t&&s.append(e,t.toString())}),t.enableInlineSync&&(s.append("sync","auto"),t.productUrl&&s.append("product_url",t.productUrl),t.forceSync&&s.append("force_sync","1"),s.append("debug","true"));const i=`${this.baseUrl}/sdk/catalog/items${s.toString()?"?"+s.toString():""}`,r={};return t.enableInlineSync&&t.productUrl&&(r["X-Product-Url"]=t.productUrl),this.request("GET",i,null,{headers:r})}async updateProductUrls(e){if(!Array.isArray(e)||0===e.length)throw new Error("Updates must be a non-empty array");const t=`${this.baseUrl}/catalog/stores/update_urls`;return this.request("POST",t,{updates:e})}async getProductUpdates(){const e=`${this.baseUrl}/catalog/stores/get_updates`;return this.request("GET",e)}async healthCheck(){const e=`${this.baseUrl}/sdk/health`;return this.request("GET",e)}async syncProduct(e,t,s=!1){if(!e||!t)throw new Error("EAN and product URL are required for synchronization");const i=`${this.config.apiBaseUrl}/partners-stores/sync`,r={ean:e.toString(),url:t};return s&&(r.force_sync=!0),this.request("POST",i,r,{headers:{}})}async get(e,t={},s={}){if("/catalog/items"===e&&t.ean){const e=await this.shouldSkipEan(t.ean);if(this.debug(`[ViprosSDK] get() method - shouldSkip: ${e}`),e)return this.debug("[ViprosSDK] get() method - returning empty items, API call skipped (bloom filter)"),{items:[],metadata:{bloomFilter:{skipped:!0,reason:"NOT_IN_FILTER",ean:t.ean}}}}if("/catalog/items"===e)return this.debug("[ViprosSDK] get() method - calling getCatalogItems() with options:",s),this.getCatalogItems(t,s);const i=`${this.baseUrl}${e}`,r=new URLSearchParams;Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&r.append(e,t.toString())});const n=r.toString()?`${i}?${r.toString()}`:i;return this.request("GET",n)}async request(e,t,s=null,i={}){return new Promise((r,n)=>{const a={method:e,url:t,data:s,options:{retry:!0,...i},resolve:r,reject:n,attempts:0};this.requestQueue.push(a),this.processQueue()})}async processQueue(){if(!this.isProcessingQueue&&0!==this.requestQueue.length){for(this.isProcessingQueue=!0;this.requestQueue.length>0;){const e=this.requestQueue.shift();try{const t=await this.executeRequest(e);e.resolve(t)}catch(t){e.options.retry&&this.shouldRetry(t,e)?await this.scheduleRetry(e):e.reject(t)}if(null!==this.rateLimitInfo.remaining&&this.rateLimitInfo.remaining<=1){const e=this.calculateRateLimitDelay();e>0&&await this.sleep(e)}}this.isProcessingQueue=!1}}async executeRequest(e){const{method:t,url:s,data:i,options:r}=e;e.attempts++;const n={method:t,headers:{...this.defaultHeaders,...r.headers},credentials:"omit"};if(!i||"POST"!==t&&"PUT"!==t&&"PATCH"!==t||(n.body=JSON.stringify(i)),r.timeout){const e=new AbortController;n.signal=e.signal,setTimeout(()=>e.abort(),r.timeout)}const a=Date.now();try{const e=await fetch(s,n),i=Date.now()-a;if(this.updateRateLimitInfo(e),!e.ok){const t=await this.handleErrorResponse(e);throw this.emit("error",t),t}const r=await e.json();return this.emit("response",{url:s,method:t,status:e.status,responseTime:i,data:r}),r}catch(e){if("AbortError"===e.name)throw this.createNetworkError("TIMEOUT",`Request timeout after ${r.timeout}ms`,s,t);if("TypeError"===e.name&&e.message.includes("fetch"))throw this.createNetworkError("NETWORK_ERROR","Network error - please check your connection",s,t,e);throw e}}async handleErrorResponse(e){const t=e.headers.get("content-type");let s;try{s=t&&t.includes("application/json")?await e.json():{message:await e.text()}}catch(t){s={message:`HTTP ${e.status}`}}const i=new Error(s.message||`HTTP ${e.status}`);switch(i.status=e.status,i.code=s.code||e.status,i.url=e.url,i.data=s,e.status){case 400:i.type="VALIDATION_ERROR";break;case 401:i.type="AUTHENTICATION_ERROR";break;case 403:i.type="AUTHORIZATION_ERROR";break;case 404:i.type="NOT_FOUND";break;case 429:i.type="RATE_LIMIT_ERROR",i.retryAfter=parseInt(e.headers.get("Retry-After"))||60;break;case 500:i.type="SERVER_ERROR";break;case 502:case 503:case 504:i.type="SERVICE_UNAVAILABLE";break;default:i.type="UNKNOWN_ERROR"}return i}shouldRetry(e,t){if(t.attempts>=this.retryConfig.maxRetries)return!1;if(!t.options.retry)return!1;if(429===e.status||"RATE_LIMIT_ERROR"===e.type)return!1;const s=["SERVER_ERROR","SERVICE_UNAVAILABLE","TIMEOUT","NETWORK_ERROR"];return[500,502,503,504].includes(e.status)||s.includes(e.type)||s.includes(e.code)}async scheduleRetry(e){const t=this.calculateRetryDelay(e);await this.sleep(t),this.requestQueue.unshift(e)}calculateRetryDelay(e){const t=this.retryConfig.baseDelay*Math.pow(2,e.attempts-1),s=1e3*Math.random();return Math.min(t+s,this.retryConfig.maxDelay)}calculateRateLimitDelay(){if(!this.rateLimitInfo.resetTime)return 0;const e=Date.now(),t=1e3*this.rateLimitInfo.resetTime;return Math.max(0,t-e+1e3)}updateRateLimitInfo(e){const t=e.headers.get("X-RateLimit-Limit"),s=e.headers.get("X-RateLimit-Remaining"),i=e.headers.get("X-RateLimit-Reset");t&&(this.rateLimitInfo.limit=parseInt(t)),s&&(this.rateLimitInfo.remaining=parseInt(s)),i&&(this.rateLimitInfo.resetTime=parseInt(i))}sleep(e){return new Promise(t=>setTimeout(t,e))}getRateLimitInfo(){return{...this.rateLimitInfo}}getQueueStatus(){return{queueLength:this.requestQueue.length,isProcessing:this.isProcessingQueue}}clearQueue(){this.requestQueue.forEach(e=>{e.reject(new Error("Request queue cleared"))}),this.requestQueue=[],this.isProcessingQueue=!1}createNetworkError(e,t,s,i,r=null){const n=new Error(t);return n.code=e,n.url=s,n.method=i,r&&(n.originalError=r),n}destroy(){this.clearQueue(),this.removeAllListeners()}async shouldSkipEan(e){try{if(this.debug("[ViprosSDK] Bloom filter check for EAN:",e),await this.loadBloomFilter(),!this.bloomFilter)return this.debug("[ViprosSDK] No bloom filter available, allowing API call"),!1;const t=this.bloomFilter.test(e),s=!t;return this.debug(`[ViprosSDK] Bloom filter test for ${e}: ${t}, shouldSkip: ${s}`),s}catch(e){return this.debug("[ViprosSDK] Bloom filter error:",e?.message||e),!1}}async loadBloomFilter(){return this.bloomLoaded?this.bloomFilter:(this.bloomLoadPromise||(this.bloomLoadPromise=(async()=>{try{const e=this.getStorage();if(e){const t=e.getItem("vipros_bloom"),s=e.getItem("vipros_bloom_time");if(t&&s&&Date.now()-parseInt(s,10)<864e5)return this.bloomFilter=new V(this.base64ToUint8Array(t),{debug:this.isDebugEnabled()}),this.debug("[ViprosSDK] Bloom filter loaded from cache"),this.bloomLoaded=!0,this.bloomFilter}const t=await fetch(`${this.baseUrl}/sdk/bloom`,{headers:{Accept:"application/octet-stream","x-api-key":this.config.apiKey}});if(!t.ok)return this.debug("[ViprosSDK] Unable to download bloom filter, status:",t.status),this.bloomFilter=null,this.bloomLoaded=!0,this.bloomFilter;const s=await t.arrayBuffer(),i=new Uint8Array(s);return this.bloomFilter=new V(i,{debug:this.isDebugEnabled()}),e&&(e.setItem("vipros_bloom",this.uint8ArrayToBase64(i)),e.setItem("vipros_bloom_time",Date.now().toString())),this.debug("[ViprosSDK] Bloom filter downloaded and cached"),this.bloomLoaded=!0,this.bloomFilter}catch(e){return this.debug("[ViprosSDK] Bloom filter unavailable:",e?.message||e),this.bloomFilter=null,this.bloomLoaded=!0,this.bloomFilter}finally{this.bloomLoadPromise=null}})()),this.bloomLoadPromise)}uint8ArrayToBase64(e){if("undefined"!=typeof globalThis&&globalThis.Buffer)return globalThis.Buffer.from(e).toString("base64");let t="";for(let s=0;s<e.length;s+=32768){const i=e.subarray(s,s+32768);let r="";for(let e=0;e<i.length;e++)r+=String.fromCharCode(i[e]);t+=r}return btoa(t)}base64ToUint8Array(e){if("undefined"!=typeof globalThis&&globalThis.Buffer)return new Uint8Array(globalThis.Buffer.from(e,"base64"));const t=atob(e),s=t.length,i=new Uint8Array(s);for(let e=0;e<s;e++)i[e]=t.charCodeAt(e);return i}getStorage(){if("undefined"==typeof window||!window.localStorage)return null;try{const e="__vipros_storage_test__";return window.localStorage.setItem(e,"1"),window.localStorage.removeItem(e),window.localStorage}catch(e){return this.debug("[ViprosSDK] localStorage unavailable:",e?.message||e),null}}debug(...e){this.isDebugEnabled()}isDebugEnabled(){return Boolean(this.config&&this.config.debug)}}var N=Object.freeze({__proto__:null,default:x});class z extends a{constructor(e=3e5){super(),("number"!=typeof e||isNaN(e)||e<0)&&(e=3e5),this.cacheTimeout=e,this.memoryCache=new Map,this.setupCleanupInterval()}get(e,t=!0){const s=this.buildKey(e);let i=this.memoryCache.get(s);return i&&this.isValidCacheEntry(i)?(i.hits=(i.hits||0)+1,i.lastAccessTime=Date.now(),this.emit("hit",{key:e,source:"memory"}),i.data):(this.emit("miss",{key:e}),null)}set(e,t,s={}){const i=this.buildKey(e),r=this.createCacheEntry(t,s);this.memoryCache.set(i,r),this.emit("set",{key:e,size:this.estimateSize(t)}),this.enforceCacheLimits()}createCacheEntry(e,t={}){const s=Date.now(),i=t.ttl||this.cacheTimeout;return{data:e,timestamp:s,expires:i>0?s+i:null,hits:0,lastAccessTime:s,size:this.estimateSize(e),tags:t.tags||[],version:t.version||"3.0.0"}}isValidCacheEntry(e){return!(!e||"object"!=typeof e)&&(!(!e.timestamp||!e.data)&&!(e.expires&&Date.now()>e.expires))}estimateSize(e){try{return JSON.stringify(e).length}catch(e){return 0}}buildKey(e){return`vipros_sdk_${e}`}has(e){const t=this.buildKey(e);if(this.memoryCache.has(t)){const e=this.memoryCache.get(t);return this.isValidCacheEntry(e)}return!1}delete(e){const t=this.buildKey(e),s=this.memoryCache.delete(t);return s&&this.emit("delete",{key:e}),s}clear(){const e=this.memoryCache.size;this.memoryCache.clear(),this.emit("clear",{memorySize:e})}size(){return this.memoryCache.size}getStats(){const e={entries:this.memoryCache.size,totalSize:0,avgSize:0};for(const[,t]of this.memoryCache)e.totalSize+=t.size||0;return e.entries>0&&(e.avgSize=Math.round(e.totalSize/e.entries)),{memory:e}}enforceCacheLimits(){const e=10485760;this.memoryCache.size>100&&this.evictLeastRecentlyUsed(this.memoryCache.size-100);let t=0;for(const[,e]of this.memoryCache)t+=e.size||0;t>e&&this.evictLargestEntries(t-e)}evictLeastRecentlyUsed(e){Array.from(this.memoryCache.entries()).map(([e,t])=>({key:e,lastAccess:t.lastAccessTime||0})).sort((e,t)=>e.lastAccess-t.lastAccess).slice(0,e).forEach(({key:e})=>{this.memoryCache.delete(e)}),this.emit("lru_eviction",{count:e})}evictLargestEntries(e){const t=Array.from(this.memoryCache.entries()).map(([e,t])=>({key:e,entry:t})).sort((e,t)=>(t.entry.size||0)-(e.entry.size||0));let s=0,i=0;for(const{key:r,entry:n}of t){if(s>=e)break;this.memoryCache.delete(r),s+=n.size||0,i++}this.emit("size_eviction",{evicted:i,freedSize:s})}setupCleanupInterval(){"undefined"!=typeof window&&setInterval(()=>{this.cleanupExpiredEntries()},6e4)}cleanupExpiredEntries(){let e=0;const t=Date.now();for(const[s,i]of this.memoryCache)i.expires&&t>i.expires&&(this.memoryCache.delete(s),e++);e>0&&this.emit("cleanup",{cleaned:e})}destroy(){this.clear(),this.removeAllListeners()}}class K extends a{constructor(e,t,s={}){super(),this.apiClient=e,this.cacheService=t,this.config={debug:s.debug||!1,retryDelayMs:5e3,maxRetries:2,...s},this.stats={attempted:0,successful:0,failed:0,skipped:0,rateLimited:0,errors:[]}}syncProductInBackground(e,t){e&&t?this.performSync(e,t).catch(e=>{this.config.debug}):this.config.debug}async performSync(e,t,s=0){this.stats.attempted++;try{const s=await this.apiClient.syncProduct(e,t);if(200===s.code)return this.stats.successful++,this.emit("syncSuccess",{ean:e,productUrl:t,result:s,timestamp:new Date}),this.config.debug,{status:"success",result:s};if(202===s.code)return this.stats.skipped++,this.emit("syncSkipped",{ean:e,reason:"server_cooldown",remaining_hours:s.remaining_hours,next_sync_at:s.next_sync_at}),this.config.debug,{status:"skipped",reason:"server_cooldown"};throw new Error(`API returned status ${s.code}: ${s.message||"Unknown error"}`)}catch(i){return this.handleSyncError(e,t,i,s)}}handleSyncError(e,t,s,i){this.stats.failed++;const r=this.categorizeError(s);return"RATE_LIMIT"===r?(this.stats.rateLimited++,this.emit("syncRateLimited",{ean:e,productUrl:t,error:s,retryAfter:s.retryAfter||60}),this.config.debug,{status:"rate_limited",error:s.message}):"NETWORK_ERROR"===r&&i<this.config.maxRetries?(this.config.debug,setTimeout(()=>{this.performSync(e,t,i+1).catch(()=>{})},this.config.retryDelayMs),{status:"retrying",attempt:i+1}):(this.logError(e,s,r),this.emit("syncError",{ean:e,productUrl:t,error:s,errorType:r,retryCount:i}),this.config.debug,{status:"error",error:s.message,errorType:r})}categorizeError(e){return 429===e.status||"RATE_LIMIT_ERROR"===e.type?"RATE_LIMIT":e.status>=500||"SERVER_ERROR"===e.type?"SERVER_ERROR":"NETWORK_ERROR"===e.code||"NetworkError"===e.name?"NETWORK_ERROR":400===e.status||"VALIDATION_ERROR"===e.type?"VALIDATION_ERROR":"UNKNOWN"}logError(e,t,s){this.stats.errors.push({ean:e,error:t.message,type:s,timestamp:Date.now()}),this.stats.errors.length>100&&(this.stats.errors=this.stats.errors.slice(-50))}getSyncStats(){return{...this.stats,successRate:this.stats.attempted>0?(this.stats.successful/this.stats.attempted*100).toFixed(2)+"%":"0%"}}clearSyncStats(){this.stats={attempted:0,successful:0,failed:0,skipped:0,rateLimited:0,errors:[]}}async forceSyncNow(e,t){return this.performSyncWithForce(e,t)}async performSyncWithForce(e,t){this.stats.attempted++;try{const s=await this.apiClient.syncProduct(e,t,!0);if(200===s.code)return this.stats.successful++,this.emit("syncSuccess",{ean:e,productUrl:t,result:s,forced:!0,timestamp:new Date}),{status:"success",result:s,forced:!0};throw new Error(`API returned status ${s.code}: ${s.message||"Unknown error"}`)}catch(s){return this.stats.failed++,this.logError(e,s,"forced_sync"),this.emit("syncError",{ean:e,productUrl:t,error:s,forced:!0}),{status:"error",error:s.message,forced:!0}}}destroy(){this.clearSyncStats(),this.removeAllListeners()}}class F extends a{constructor(){if(super(),this.version="3.0.0-unified",this.isInitialized=!1,this.config={apiKey:null,debug:!1,syncEnabled:!0,inlineSyncEnabled:!0,disableBackgroundSync:!0,containerSelector:"[data-ean]",autoScan:!0},this._apiClient=null,this._cacheService=null,this._syncService=null,this._servicesInitialized=!1,this.stats={version:this.version,componentsRegistered:0,componentsActive:0,offersLoaded:0,errors:0,cacheHits:0,apiCalls:0,syncAttempts:0,syncSuccess:0},this.cache=new Map,this.eventListeners=new Map,F.instance)return F.instance;F.instance=this}static getInstance(){return F.instance||(F.instance=new F),F.instance}init(e={}){return this.isInitialized?(this.debugLog("SDK déjà initialisé"),this):(this.config=n.create({...this.config,...e}),this.debugLog(`🚀 Initialisation VIPros SDK v${this.version}`),this.debugLog("Configuration:",this.config),this.registerWebComponents(),this.config.autoScan&&this.scanAndConvert(),this.isInitialized=!0,this.emitEvent("sdk-ready",{version:this.version,config:this.config}),this.debugLog("🎯 SDK initialisé avec lazy loading - services créés à la demande"),this)}get apiClient(){return this._apiClient||(this.debugLog("📡 Création lazy d'ApiClient"),this._apiClient=new x(this.config)),this._apiClient}get cacheService(){return this._cacheService||(this.debugL