@vipros-org/sdk 3.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -30,9 +30,9 @@ No npm install required. Add this to your HTML:
30
30
  <script src="https://cdn.jsdelivr.net/npm/@vipros-org/sdk@latest/vipros-sdk.min.js"></script>
31
31
 
32
32
  <script>
33
- ViprosSDK.init({
34
- apiKey: 'your-api-key'
35
- });
33
+ ViprosSDK.init({
34
+ apiKey: "your-api-key",
35
+ });
36
36
  </script>
37
37
 
38
38
  <vipros-offer-card ean="4007123684731" price="89.99"></vipros-offer-card>
@@ -41,21 +41,8 @@ No npm install required. Add this to your HTML:
41
41
  ## Optional CSS
42
42
 
43
43
  ```html
44
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@vipros-org/sdk@latest/vipros-sdk.min.css">
44
+ <link
45
+ rel="stylesheet"
46
+ href="https://cdn.jsdelivr.net/npm/@vipros-org/sdk@latest/vipros-sdk.min.css"
47
+ />
45
48
  ```
46
-
47
- ## API
48
-
49
- | Method | Description |
50
- |--------|-------------|
51
- | `ViprosSDK.init(config)` | Initialize with API key |
52
- | `ViprosSDK.getProductData(ean)` | Get product data |
53
- | `ViprosSDK.getStats()` | Runtime statistics |
54
- | `ViprosSDK.clearCache()` | Clear cached data |
55
- | `ViprosSDK.refreshAll()` | Refresh all cards |
56
- | `ViprosSDK.on(event, cb)` | Listen for events |
57
-
58
- ## Support
59
-
60
- - Email: tech@vipros.fr
61
- - Issues: https://github.com/Do-It-VIPros/vipros-connect/issues
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vipros-org/sdk",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "description": "VIPros Partner SDK - Cashback and loyalty points integration for e-commerce",
5
5
  "main": "vipros-sdk.min.js",
6
6
  "module": "vipros-sdk.js",
@@ -18,12 +18,8 @@
18
18
  "e-commerce",
19
19
  "vipoints"
20
20
  ],
21
- "author": "VIPros <tech@vipros.fr>",
21
+ "author": "VIPros",
22
22
  "license": "UNLICENSED",
23
- "repository": {
24
- "type": "git",
25
- "url": "https://github.com/Do-It-VIPros/vipros-connect.git"
26
- },
27
23
  "homepage": "https://vipros.fr",
28
24
  "publishConfig": {
29
25
  "access": "public",
package/vipros-sdk.css CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * VIPros SDK - CSS File
3
3
  * Version: 3.0.0-unified
4
- * Generated: 2026-02-10T11:29:54.359Z
4
+ * Generated: 2026-02-10T14:41:01.928Z
5
5
  */
6
6
 
7
7
  /* VIPros SDK Base Styles */
package/vipros-sdk.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * VIPros SDK v3.0.0-unified - Production Build
3
- * Generated: 2026-02-10T11:29:53.281Z
3
+ * Generated: 2026-02-10T14:41:00.786Z
4
4
  * Environment: Production
5
5
  */
6
6
  var ViprosSDK = (function () {
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * VIPros SDK - CSS File
3
3
  * Version: 3.0.0-unified
4
- * Generated: 2026-02-10T11:29:54.359Z
4
+ * Generated: 2026-02-10T14:41:01.928Z
5
5
  */
6
6
 
7
7
  /* VIPros SDK Base Styles */
package/vipros-sdk.min.js CHANGED
@@ -1,2 +1,2 @@
1
- /*! VIPros SDK v3.0.0-unified - Production Minified - 2026-02-10T11:29:53.281Z */
1
+ /*! VIPros SDK v3.0.0-unified - Production Minified - 2026-02-10T14:41:00.786Z */
2
2
  var ViprosSDKBundle=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},I=function(e,t){var s=t/8|0;return(e[s]|e[s+1]<<8|e[s+2]<<16)>>(7&t)},D=function(e){return(e+7)/8|0},T=["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||T[e]);if(i.code=e,Error.captureStackTrace&&Error.captureStackTrace(i,_),!s)throw i;return i},B=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 T=A(e,m+1,3);if(m+=3,!T){var B=e[(M=D(m)+4)-4]|e[M-3]<<8,U=M+B;if(U>r){c&&_(0);break}a&&l(f+B),s.set(e.subarray(M,U),f),t.b=f+=B,t.p=m=8*U,t.f=p;continue}if(1==T)b=k,v=L,C=9,S=5;else if(2==T){var O=A(e,m,31)+257,V=A(e,m+10,15)+4,P=O+A(e,m+5,31)+1;m+=14;for(var $=new o(P),x=new o(19),N=0;N<V;++N)x[d[N]]=A(e,m+3*N,7);m+=3*V;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)$[N++]=M;else{var j=0,W=0;for(16==M?(W=3+A(e,m,3),m+=2,j=$[N-1]):17==M?(W=3+A(e,m,7),m+=3):18==M&&(W=11+A(e,m,127),m+=7);W--;)$[N++]=j}}var Q=$.subarray(0,O),H=$.subarray(O);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[I(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[I(e,m)&X],se=te>>4;te||_(3),m+=15&te;H=y[se];if(se>3){ee=u[se];H+=I(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 O(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"),B(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 V(e,t){return B(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 ${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 V(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 O(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 getCatalogItemByEan(e,t={}){this.debug("[ViprosSDK] getCatalogItemByEan() called with ean:",e,"options:",t);if(await this.shouldSkipEan(e))return this.debug("[ViprosSDK] getCatalogItemByEan() - EAN not in bloom filter, skipping API call"),null;const s=new URLSearchParams;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=s.toString(),r=`${this.baseUrl}/sdk/catalog/items/${encodeURIComponent(e)}${i?"?"+i:""}`,n={};t.enableInlineSync&&t.productUrl&&(n["X-Product-Url"]=t.productUrl);try{const t=await this.request("GET",r,null,{headers:n});return 404!==t.code&&t.item?(this.debug("[ViprosSDK] getCatalogItemByEan() - Product found:",t.item?.name),t.item):(this.debug("[ViprosSDK] getCatalogItemByEan() - Product not found for EAN:",e),null)}catch(e){return this.debug("[ViprosSDK] getCatalogItemByEan() - Error:",e?.message||e),null}}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){if(t.ean&&!t.ean.includes(",")){this.debug("[ViprosSDK] get() method - using optimized single EAN route");const e=await this.getCatalogItemByEan(t.ean,s);return e?{items:[e],code:200}:{items:[],code:404,metadata:{ean:t.ean,optimizedRoute:!0}}}if(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}}}}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 $(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 $(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 ViprosSDK 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,ViprosSDK.instance)return ViprosSDK.instance;ViprosSDK.instance=this}static getInstance(){return ViprosSDK.instance||(ViprosSDK.instance=new ViprosSDK),ViprosSDK.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.debugLog("💾 Création lazy de CacheService"),this._cacheService=new z(this.config.cacheTimeout||3e5)),this._cacheService}get syncService(){return!this._syncService&&this.config.syncEnabled&&(this.debugLog("🔄 Création lazy d'EanSyncService"),this._syncService=new K(this.apiClient,this.cacheService,this.config),this.setupSyncEvents()),this._syncService}initializeServicesEager(){this.debugLog("🚀 Initialisation eager de tous les services...");const e=this.apiClient,t=this.cacheService,s=this.syncService;return this._servicesInitialized=!0,this.debugLog("✅ Tous les services initialisés (eager)"),{api:e,cache:t,sync:s}}setupSyncEvents(){this.syncService&&(this.syncService.on("syncSuccess",e=>{this.stats.syncSuccess++,this.emit("syncSuccess",e)}),this.syncService.on("syncSkipped",e=>{this.emit("syncSkipped",e)}),this.syncService.on("syncError",e=>{this.emit("syncError",e)}),this.syncService.on("syncRateLimited",e=>{this.emit("syncRateLimited",e)}),this.debugLog("Événements de synchronisation connectés"))}getCacheService(){return this.cacheService}syncProductInBackground(e,t){this.config.disableBackgroundSync?this.debugLog("Sync en arrière-plan désactivée (disableBackgroundSync=true)"):this.syncService?(this.stats.syncAttempts++,this.debugLog(`Déclenchement sync pour EAN ${e}`),this.syncService.syncProductInBackground(e,t)):this.debugLog("Sync demandée mais service non disponible")}registerWebComponents(){customElements.get("vipros-offer-card")||(r.setSDKInstance(this),customElements.define("vipros-offer-card",r),this.stats.componentsRegistered++,this.debugLog("✅ vipros-offer-card registered"))}scanAndConvert(){const e=document.querySelectorAll(this.config.containerSelector);this.debugLog(`🔍 Scan: ${e.length} containers data-ean trouvés`),e.forEach(e=>{const t=e.getAttribute("data-ean"),s=e.getAttribute("data-price");if(t){const i=document.createElement("vipros-offer-card");i.setAttribute("ean",t),s&&i.setAttribute("price",s),e.parentNode.replaceChild(i,e),this.debugLog(`🔄 Converti data-ean="${t}" vers Web Component`)}})}getApiClient(){return this.apiClient}getServicesStatus(){return{apiClientInitialized:!!this._apiClient,cacheServiceInitialized:!!this._cacheService,syncServiceInitialized:!!this._syncService,allServicesEager:this._servicesInitialized}}async getProductData(e){const t=`product_${e}`;if(this.cache.has(t)){const s=this.cache.get(t);if(Date.now()-s.timestamp<this.config.cacheTimeout)return this.stats.cacheHits++,this.debugLog(`💾 Cache hit for EAN ${e}`),s.data}try{this.stats.apiCalls++;const s=await this.apiClient.getCatalogItemByEan(e),i=s?{code:200,item:s}:{code:404,item:null};return s&&this.cache.set(t,{data:i,timestamp:Date.now()}),this.debugLog(`📡 API data loaded for EAN ${e} (optimized route)`),i}catch(t){throw this.stats.errors++,this.debugLog(`❌ Erreur API pour EAN ${e}:`,t),t}}emitEvent(e,t={}){const s=`vipros-${e}`,i=new CustomEvent(s,{detail:t,bubbles:!0,cancelable:!0});document.dispatchEvent(i),this.debugLog(`📤 Event: ${s}`,t)}on(e,t){const s=`vipros-${e}`;document.addEventListener(s,t),this.eventListeners.has(s)||this.eventListeners.set(s,[]),this.eventListeners.get(s).push(t)}off(e,t){const s=`vipros-${e}`;if(document.removeEventListener(s,t),this.eventListeners.has(s)){const e=this.eventListeners.get(s),i=e.indexOf(t);i>-1&&e.splice(i,1)}}clearCache(){this.cache.clear(),this.debugLog("🗑️ Cache vidé")}refreshAll(){const e=document.querySelectorAll("vipros-offer-card");e.forEach(e=>{e.refresh&&"function"==typeof e.refresh&&e.refresh()}),this.debugLog(`🔄 Refresh de ${e.length} composants`)}getStats(){return this.stats.componentsActive=document.querySelectorAll("vipros-offer-card").length,{...this.stats}}debugLog(e,t=null){this.config.debug}destroy(){this.eventListeners.forEach((e,t)=>{e.forEach(e=>{document.removeEventListener(t,e)})}),this.eventListeners.clear(),this.cache.clear(),this._apiClient&&(this.debugLog("🧹 Nettoyage ApiClient"),this._apiClient=null),this._cacheService&&(this.debugLog("🧹 Nettoyage CacheService"),this._cacheService=null),this._syncService&&(this.debugLog("🧹 Nettoyage SyncService"),this._syncService=null),this._servicesInitialized=!1,this.isInitialized=!1,this.debugLog("🔥 SDK détruit avec nettoyage des services lazy")}}const F=new ViprosSDK;return"undefined"!=typeof window&&(window.ViprosSDK=F),F}();"undefined"!=typeof window&&void 0!==ViprosSDKBundle&&(window.ViprosSDK=ViprosSDKBundle);