mk-sdk-git 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # mk-sdk
2
+
3
+ SDK de tracking de e-commerce + try-on da MetaKosmos. Um único `<script>` que
4
+ roda em todas as páginas da loja: mede a jornada de compra (visita → produto →
5
+ carrinho → compra) e injeta o botão de provador virtual de forma zero-touch.
6
+
7
+ ## Instalação
8
+
9
+ Uma linha antes de `</head>`, em todas as páginas:
10
+
11
+ ```html
12
+ <script src="https://collector.metakosmos.com.br/sdk/mk-sdk.js"
13
+ data-mk-project="SEU_PROJECT_ID"
14
+ data-mk-product="mk-fashion"
15
+ async></script>
16
+ ```
17
+
18
+ - `data-mk-project` — ID do projeto (obrigatório).
19
+ - `data-mk-product` — produto MetaKosmos da página (`mk-fashion`, `mk-beauty`,
20
+ `mk-3d`…). Opcional; default `mk-fashion`.
21
+
22
+ ## Configuração
23
+
24
+ Lida do `<script>` (`data-mk-*`) ou de `window.__MK` antes do boot:
25
+
26
+ | Campo | Origem | Default |
27
+ |---|---|---|
28
+ | `projectId` | `data-mk-project` / `__MK.projectId` | — (obrigatório) |
29
+ | `product` | `data-mk-product` / `__MK.product` | `mk-fashion` |
30
+ | `collectorUrl` | `data-mk-collector` / `__MK.collectorUrl` | `collector.metakosmos.com.br` |
31
+ | `apiUrl` | `__MK.apiUrl` | `mkfashion-new-api.mk3dlabs.com` |
32
+ | `debug` | `data-mk-debug` / `?mkdebug` | `false` |
33
+ | `anchor` | `__MK.anchor` | `null` (cai no CMS/heurística) |
34
+
35
+ ## API pública (`window.mk`)
36
+
37
+ ```js
38
+ mk.open({ projectId, identifier }); // abre o provador
39
+ mk.close();
40
+ mk.isAvailable(projectId, identifier);
41
+ mk.onReady(cb); mk.onAddToCart(cb); mk.onProductLoaded(cb); /* … */
42
+ ```
43
+
44
+ ## Coleta
45
+
46
+ Eventos vão em batch (2s ou 20 eventos) para `POST {collectorUrl}/v1/track`
47
+ com header `X-MK-Project-Id`. Dados pessoais (e-mail, CPF, telefone, etc.) são
48
+ descartados antes do envio.
49
+
50
+ ## Build
51
+
52
+ ```bash
53
+ npm install
54
+ npm run build # gera dist/mk-sdk.js
55
+ npm run build:ext # gera dist + copia pra extension/mk-sdk.js
56
+ npm run build:watch # rebuild em watch
57
+ ```
58
+
59
+ ## Extensão de QA
60
+
61
+ `extension/` é uma extensão Chrome que injeta o `mk-sdk` em qualquer loja para
62
+ validar a integração (tracking, detecção de plataforma/SKU, picker de posição
63
+ do botão) sem a marca precisar instalar o script. Veja `extension/README.md`.
64
+
65
+ ## Testes
66
+
67
+ ```bash
68
+ node scripts/test-3variants.js
69
+ node scripts/test-save-nojump.js
70
+ node scripts/test-api-anchor.js
71
+ # … demais scripts em scripts/
72
+ ```
package/dist/mk-sdk.js ADDED
@@ -0,0 +1 @@
1
+ (()=>{var Te=Object.defineProperty;var A=(t,e)=>{for(var r in e)Te(t,r,{get:e[r],enumerable:!0})};var ot={collectorUrl:"https://collector.metakosmos.com.br",appUrl:"https://mkfashion.mk3dlabs.com/visualizer",apiUrl:"https://mkfashion-new-api.mk3dlabs.com"},Ee={},B=null;function rt(){if(B)return B;let t=null;try{t=document.currentScript||document.querySelector("script[data-mk-project]")||document.querySelector('script[src*="mk-sdk"]')||document.querySelector('script[src*="mk-pixel"]')}catch(i){}let e=i=>{try{return t&&t.getAttribute(i)}catch(a){return null}},r=e("data-mk-project")||e("data-mk-client")||window.__MK&&(window.__MK.projectId||window.__MK.clientSlug)||null,o=e("data-mk-product")||window.__MK&&window.__MK.product||"mk-fashion",n=e("data-mk-collector")||window.__MK&&window.__MK.collectorUrl||Ee.collectorUrl||ot.collectorUrl;return B={projectId:r,product:o,collectorUrl:n,appUrl:window.__MK&&window.__MK.appUrl||ot.appUrl,apiUrl:window.__MK&&window.__MK.apiUrl||ot.apiUrl,debug:!!(e("data-mk-debug")!==null||window.__MK&&window.__MK.debug||/[?&]mkdebug\b/.test(location.search)),observe:!!(window.__MK&&window.__MK.observe),forceButton:!!(window.__MK&&window.__MK.forceButton),anchor:window.__MK&&window.__MK.anchor||null,cartRedirect:!(window.__MK&&window.__MK.cartRedirect===!1),autoTrack:e("data-mk-no-autotrack")===null,batchIntervalMs:2e3,batchMaxSize:20,engagementIntervalMs:15e3},B}function f(){return B||rt()}function m(...t){let e=f();e&&e.debug&&typeof console!="undefined"&&console.log("[mk-sdk]",...t)}var Lt="_mk_vid",It="_mk_sid",j=null,N=null;function z(){return typeof crypto!="undefined"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{let e=Math.random()*16|0;return(t==="x"?e:e&3|8).toString(16)})}function Rt(){if(j)return j;try{let t=localStorage.getItem(Lt);return t||(t="v_"+z(),localStorage.setItem(Lt,t)),j=t,t}catch(t){return j="v_"+z(),j}}function Pt(){if(N)return N;try{let t=sessionStorage.getItem(It);return t||(t="s_"+z(),sessionStorage.setItem(It,t)),N=t,t}catch(t){return N="s_"+z(),N}}var Bt=[/email/i,/e-?mail/i,/cpf/i,/cnpj/i,/phone/i,/telefone/i,/celular/i,/address/i,/endereco/i,/cep/i,/zip/i,/card/i,/cartao/i,/cvv/i,/password/i,/senha/i,/token/i,/\bnome\b/i,/fullname/i,/firstname/i,/lastname/i,/sobrenome/i,/birth/i,/nascimento/i,/rg\b/i],jt={imageUrl:1,image:1,thumbnail:1,photo:1,imageBase64:1,src:1},nt=2e3;function Nt(t){for(let e=0;e<Bt.length;e++)if(Bt[e].test(t))return!0;return!1}function Ut(t){if(!t||typeof t!="object"||Array.isArray(t))return typeof t=="string"&&t.length>nt?t.slice(0,200)+"...[truncated "+t.length+"B]":t;let e={};for(let r in t){if(!Object.prototype.hasOwnProperty.call(t,r)||Nt(r))continue;let o=t[r];if(jt[r]){e[r+"Present"]=!!o;continue}if(typeof o=="string"&&o.length>nt){e[r]=o.slice(0,200)+"...[truncated "+o.length+"B]";continue}if(o&&typeof o=="object"&&!Array.isArray(o)){e[r]=Ae(o);continue}e[r]=o}return e}function Ae(t){let e={};for(let r in t){if(!Object.prototype.hasOwnProperty.call(t,r)||Nt(r))continue;let o=t[r];if(jt[r]){e[r+"Present"]=!!o;continue}if(typeof o=="string"&&o.length>nt){e[r]=o.slice(0,200)+"...[truncated]";continue}e[r]=o}return e}var q=[],it=null,L=null;function Ot(t){L=t}function l(t,e,r){if(!f().projectId){(l._pre=l._pre||[]).push({name:t,params:e,ts:r||Date.now()}),l._pre.length>50&&l._pre.shift();return}if(l._pre&&l._pre.length){let n=l._pre;l._pre=[];for(let i of n)Mt(i.name,i.params,i.ts)}Mt(t,e,r)}function Mt(t,e,r){let o=f(),n=Ut(e||{}),i="page_"+Le(t);if(q.push({name:i,ts:r||Date.now(),params:n}),m("queued",t,n),o.observe)try{window.postMessage({__mkpixel:!0,event:{name:i,params:n},site:L?{pageType:L.pageType,platform:L.platform,url:L.url}:null},"*")}catch(a){}if(q.length>=o.batchMaxSize){U();return}it||(it=setTimeout(()=>{it=null,U()},o.batchIntervalMs))}function Le(t){if(typeof t!="string"||!t)return"unknown";let e=t.replace(/^on/,"");return e=e.replace(/[A-Z]/g,(r,o)=>(o>0?"_":"")+r.toLowerCase()),e.indexOf("page_")===0&&(e=e.slice(5)),e}function U(t){if(q.length===0)return;let e=f();if(!e.projectId||!e.collectorUrl)return;let r=q.splice(0,50),o=JSON.stringify({product:e.product||void 0,visitorId:Rt(),sessionId:Pt(),events:r,site:L||void 0}),n=e.collectorUrl+"/v1/track";if(t&&navigator.sendBeacon)try{let i=new Blob([o],{type:"application/json"});navigator.sendBeacon(n+"?projectId="+encodeURIComponent(e.projectId),i);return}catch(i){}fetch(n,{method:"POST",keepalive:!0,headers:{"Content-Type":"application/json","X-MK-Project-Id":e.projectId},body:o}).catch(()=>{})}function Ft(){try{window.addEventListener("pagehide",()=>U(!0)),window.addEventListener("beforeunload",()=>U(!0)),document.addEventListener("visibilitychange",()=>{document.hidden&&U(!0)})}catch(t){}}function k(t){let e=[];try{let r=document.querySelectorAll('script[type="application/ld+json"]');for(let o of r){let n;try{n=JSON.parse(o.textContent)}catch(a){continue}let i=[];Array.isArray(n)?i.push(...n):n["@graph"]?i.push(...n["@graph"]):i.push(n);for(let a of i){if(!a||!a["@type"])continue;let c=Array.isArray(a["@type"])?a["@type"]:[a["@type"]];(!t||t.some(u=>c.includes(u)))&&e.push(a)}}}catch(r){}return e}var at={};A(at,{addToCart:()=>Be,detect:()=>Re,id:()=>Ie,resolveSku:()=>Pe});var Ie="shopify";function Re(){return!!(window.Shopify||window.ShopifyAnalytics)}function Pe(){let t=window;return t.ShopifyAnalytics&&t.ShopifyAnalytics.meta&&t.ShopifyAnalytics.meta.product?{value:String(t.ShopifyAnalytics.meta.product.id),source:"shopify"}:null}var $=t=>String(t==null?"":t).trim().toLowerCase();async function Be({size:t,sku:e,quantity:r}){let o=(location.pathname.split("/products/")[1]||"").split(/[?#]/)[0];if(!o)throw new Error("shopify: sem handle de produto na URL (n\xE3o \xE9 PDP?)");let i=(await fetch("/products/"+o+".js").then(s=>s.json())).variants||[],a=s=>[s.option1,s.option2,s.option3,s.title].some(x=>$(x)===$(t)),c=null;if(t&&(c=i.find(s=>a(s)&&s.available)||i.find(a)),!c&&e&&(c=i.find(s=>$(s.sku)===$(e))),c||(c=i.find(s=>s.available)||i[0]),!c)throw new Error("shopify: variante n\xE3o encontrada");let u=await fetch("/cart/add.js",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({items:[{id:c.id,quantity:r||1}]})});if(!u.ok)throw new Error("shopify: /cart/add.js HTTP "+u.status);return{platform:"shopify",variantId:c.id,size:c.title,sku:c.sku||null}}var ct={};A(ct,{addToCart:()=>Me,detect:()=>Ne,id:()=>je,resolveSku:()=>Ue});var je="hybris";function Ne(){return!!(window.ACC&&window.ACC.config)}function Ue(){let t=(location.pathname||"").match(/\/p\/([^/?#]+)/);return t&&t[1]?{value:decodeURIComponent(t[1]),source:"hybris/url"}:null}var Dt=t=>String(t==null?"":t).trim().toLowerCase();async function Me({size:t,quantity:e}){let r=[...document.querySelectorAll('.js-product-select-size, a[data-code], [class*="select-size"]')].filter(h=>h.getAttribute&&h.getAttribute("data-code")),o=t?r.find(h=>Dt(h.textContent)===Dt(t)):null;o||(o=r.find(h=>h.offsetParent!==null)||r[0]);let n=o&&o.getAttribute("data-code");if(!n)throw new Error("hybris: variante (data-code) n\xE3o encontrada");let i=document.getElementById("product--add-to-cart-form")||document.querySelector('form[action*="/cart/add"]'),a=i&&i.querySelector('[name="CSRFToken"]'),c=a&&a.value,u=i&&i.getAttribute("action")||"/cart/add";if(!c)throw new Error("hybris: CSRFToken n\xE3o encontrado");let s=new URLSearchParams;s.set("productCodePost",n),s.set("qty",String(e||1)),s.set("CSRFToken",c);let x=await fetch(u,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded","X-Requested-With":"XMLHttpRequest"},body:s.toString()});if(!x.ok)throw new Error("hybris: "+u+" HTTP "+x.status);return{platform:"hybris",productCode:n,size:o.textContent.trim()}}var st={};A(st,{addToCart:()=>ze,detect:()=>Fe,id:()=>Oe,resolveSku:()=>De});var Oe="vtex";function Fe(){return!!(window.vtex||window.vtexjs||window.vtxctx||window.skuJson_0)}function De(){let t=window;return t.vtxctx&&t.vtxctx.skus&&t.vtxctx.skus[0]?{value:String(t.vtxctx.skus[0]),source:"vtex/vtxctx"}:t.skuJson_0&&t.skuJson_0.skus&&t.skuJson_0.skus[0]?{value:String(t.skuJson_0.skus[0].sku),source:"vtex/skuJson"}:null}var K=t=>String(t==null?"":t).trim().toLowerCase();async function ze({size:t,quantity:e}){let r=window.skuJson_0&&window.skuJson_0.skus||[];if(!r.length)throw new Error("vtex: skuJson_0 indispon\xEDvel");let o=i=>K(i.skuname)===K(t)||i.dimensions&&Object.values(i.dimensions).some(a=>K(a)===K(t)),n=t?r.find(i=>o(i)&&i.available)||r.find(o):null;if(n||(n=r.find(i=>i.available)||r[0]),!n)throw new Error("vtex: variante n\xE3o encontrada");if(window.vtexjs&&window.vtexjs.checkout&&window.vtexjs.checkout.addToCart)return await window.vtexjs.checkout.addToCart([{id:parseInt(n.sku,10),quantity:e||1,seller:"1"}]),{platform:"vtex",skuId:n.sku,size:n.skuname||t};throw new Error("vtex: vtexjs.checkout indispon\xEDvel")}var lt={};A(lt,{addToCart:()=>Je,detect:()=>Ke,id:()=>qe,resolveSku:()=>He,skipRedirect:()=>$e});var qe="nuvemshop",$e=!0;function Ke(){return!!(window.LS&&(window.LS.cart||window.LS.addToCart))}function He(){try{let t=window.LS,e=t&&t.variants||[],r=document.querySelector('[name="variant_id"]'),o=r&&r.value?e.find(n=>String(n.id)===String(r.value)):null;if(o||(o=e.find(n=>n.available!==!1&&n.sku)||e.find(n=>n.sku)||e[0]),o&&o.sku)return{value:String(o.sku),source:"nuvemshop/variant"};if(t&&t.product&&t.product.sku)return{value:String(t.product.sku),source:"nuvemshop/product"}}catch(t){}return null}var H=t=>String(t==null?"":t).trim().toLowerCase();async function Je({size:t,quantity:e}){let r=document.getElementById("product_form")||document.querySelector('.js-product-form, form[action*="/comprar"]');if(!r)throw new Error("nuvemshop: #product_form n\xE3o encontrado");t&&r.querySelectorAll('select[name^="variation"]').forEach(i=>{let a=[...i.options].find(c=>H(c.textContent).includes(H(t))||H(c.value)===H(t));a&&(i.value=a.value,i.dispatchEvent(new Event("change",{bubbles:!0})))});let o=r.querySelector('[name="quantity"]');return o&&e&&(o.value=String(e)),await new Promise(i=>setTimeout(i,400)),typeof r.requestSubmit=="function"?r.requestSubmit():r.submit(),{platform:"nuvemshop",variantId:(r.querySelector('[name="variant_id"]')||{}).value||null}}var ut={};A(ut,{addToCart:()=>Ye,detect:()=>We,id:()=>Ve,resolveSku:()=>Xe,skipRedirect:()=>Ge});var Ve="wake",Ge=!0;function We(){return!!(window.StorefrontClient||typeof window.addOrCreateCheckout=="function"||typeof window.addToCartClick=="function")}function Xe(){try{let t=document.querySelector('input[name="product-id"], [data-product-id]'),e=t?t.value||t.getAttribute("data-product-id"):null;if(e)return{value:String(e).trim(),source:"wake/product-id"};let r=(location.pathname||"").match(/-(\d+)\/?(?:[?#]|$)/);if(r)return{value:r[1],source:"wake/url"}}catch(t){}return null}var zt=t=>String(t==null?"":t).trim().toLowerCase();async function Ye({size:t,quantity:e}){if(t){let i=[...document.querySelectorAll("input[attribute-value]")].find(a=>zt(a.getAttribute("attribute-value"))===zt(t));if(i){try{i.checked=!0}catch(a){}try{typeof window.selectAttribute=="function"?window.selectAttribute(i):i.click()}catch(a){}await new Promise(a=>setTimeout(a,600))}}let r=document.querySelector('[name="product-variant-id"]'),o=r&&r.value;if(!o)throw new Error("wake: product-variant-id n\xE3o encontrado");if(typeof window.addOrCreateCheckout!="function")throw new Error("wake: addOrCreateCheckout indispon\xEDvel");if(!await window.addOrCreateCheckout([{productVariantId:Number(o),quantity:e||1,customization:[]}]))throw new Error("wake: addOrCreateCheckout retornou false");return{platform:"wake",productVariantId:o,size:t||null}}var pt={};A(pt,{addToCart:()=>J,detect:()=>Qe,id:()=>Ze,resolveSku:()=>dt});var Ze="generic";function Qe(){return!0}function dt(){let t=k(["Product"]);if(t[0]){let e=t[0],r=e.sku||e.mpn||e.gtin13||e.productID;if(r)return{value:String(r),source:"jsonld"}}try{let e=document.querySelector('[itemprop="sku"]');if(e){let r=e.getAttribute("content")||(e.textContent||"").trim();if(r)return{value:String(r),source:"microdata"}}}catch(e){}try{let e=window.konfidencyData;if(e&&e.product&&e.product.variants&&e.product.variants[0])return{value:String(e.product.variants[0]),source:"konfidency"}}catch(e){}return null}var to=/(adicionar\s*(à|a|ao)?\s*(sacola|carrinho|cesta|bolsa))|adicionar ao carrinho|add to (cart|bag)|comprar agora/i,eo=/continuar|como comprar|lista|desejos|favorito/i;async function J(){let t=document.querySelectorAll("button,[role=button],input[type=submit]");for(let e of t){let r=(e.textContent||e.value||"").replace(/\s+/g," ").trim();if(r&&r.length<40&&to.test(r)&&!eo.test(r))try{return e.click(),{platform:"native-click",clicked:r}}catch(o){}}return{platform:"none",error:"bot\xE3o de carrinho nativo n\xE3o encontrado"}}var Kt=[at,ct,st,lt,ut],oo=[["woocommerce",()=>!!(window.wc_add_to_cart_params||window.woocommerce_params)],["lojaintegrada",()=>!!window.LojaIntegrada]],V;function Ht(){return V||(V=Kt.find(t=>{try{return t.detect()}catch(e){return!1}})||pt,V)}function Jt(){let t=Kt.find(e=>{try{return e.detect()}catch(r){return!1}});if(t)return t.id;for(let[e,r]of oo)try{if(r())return e}catch(o){}return null}function M(){let t=Ht();if(t.id!=="generic"&&t.resolveSku)try{let e=t.resolveSku();if(e)return e}catch(e){}return dt()}async function Vt(t){t=t||{};let e={size:t.size||t.selectedSize||null,sku:t.sku||t.identifier||t.selectedIdentifier||null,quantity:t.quantity||1},r=Ht();try{let o=r.addToCart?await r.addToCart(e):await J(e);return m("cart: adicionado",o),qt(),$t(r),o}catch(o){m('cart: adapter "'+r.id+'" falhou \u2014 fallback clique nativo',o&&o.message);let n=await J(e);return qt(),$t(r),n}}function qt(){["cart:refresh","cart:updated","cart:build","ajaxProduct:added","product:added-to-cart"].forEach(t=>{try{document.dispatchEvent(new CustomEvent(t))}catch(e){}})}function $t(t){if(!f().cartRedirect||t&&t.skipRedirect)return;let r=t&&t.cartUrl||"/cart";setTimeout(()=>{try{window.location.href=r}catch(o){}},250)}var ro=/\/(thank[_-]?you|orders?\/|pedido[_-]?(confirmado|realizado|finalizado|sucesso)|sucesso|order[_-]?confirmation|compra[_-]?(finalizada|concluida)|orderplaced)/i,no=/\/checkout/i,io=/\/(cart|carrinho|sacola|bag)(\/|$|\?|#)/i,ao=/\/(products?|produtos?|p)\//i,co=/\/(collections?|categoria|categorias|c|departamento)\//i,so=/\/(search|busca|s)(\/|\?)/i;function Gt(){try{if(window.__mkPageType)return window.__mkPageType}catch(e){}try{let e=k();for(let r of e){let o=Array.isArray(r["@type"])?r["@type"]:[r["@type"]];if(o.includes("Order")||o.includes("Invoice"))return"purchase";if(o.includes("Product"))return"pdp";if(o.includes("SearchResultsPage"))return"search";if(o.includes("CollectionPage")||o.includes("ItemList"))return"category"}}catch(e){}let t=(location.pathname||"").toLowerCase();return t==="/"||t===""||t==="/home"||t==="/index.html"?"home":ro.test(t)?"purchase":no.test(t)?"checkout":io.test(t)?"cart":ao.test(t)?"pdp":co.test(t)?"category":so.test(t)?"search":"other"}function Wt(t){let e=null;try{let r=new URLSearchParams(location.search),o=["utm_source","utm_medium","utm_campaign","utm_term","utm_content"],n={};for(let i of o){let a=r.get(i);a&&(n[i.replace("utm_","")]=a)}Object.keys(n).length&&(e=n)}catch(r){}return{url:location.href,pathname:location.pathname,referrer:document.referrer||null,title:document.title||null,pageType:t,utm:e,userAgent:navigator.userAgent,language:navigator.language,viewport:window.innerWidth+"x"+window.innerHeight,platform:lo()}}function lo(){return Jt()}var ft={},uo=null,O=0,Xt=!1;function Yt(t){Xt||(Xt=!0,Zt(t),po(),fo(),mo(),ho(),go(t))}function Zt(t){ft={};let e=Gt(),r=Wt(e);if(Ot(r),l("view",{url:location.href,pathname:location.pathname,referrer:document.referrer||null,title:document.title||null,pageType:e}),typeof t=="function")try{t(e,r)}catch(o){}}function po(){if(!document.body)return;let t={A:1,BUTTON:1,INPUT:1,SELECT:1,TEXTAREA:1},e=0;document.body.addEventListener("click",r=>{try{let o=Date.now();if(o-e<100)return;e=o;let n=r.target;for(let c=0;c<5&&n&&n!==document.body&&!(t[n.tagName]||n.getAttribute&&n.getAttribute("role")==="button");c++)n=n.parentElement;if(!n||!t[n.tagName]&&!(n.getAttribute&&n.getAttribute("role")==="button"))return;let i={tag:n.tagName},a=n.tagName==="INPUT"||n.tagName==="TEXTAREA"?n.value:n.textContent;i.text=(a||"").replace(/\s+/g," ").trim().substring(0,100),n.href&&(i.href=String(n.href).substring(0,500)),n.id&&(i.id=n.id),n.className&&typeof n.className=="string"&&(i.classes=n.className.trim().substring(0,200)),l("click",i)}catch(o){}},{capture:!0,passive:!0})}function fo(){let t=[25,50,75,100],e=null,r=()=>{try{let o=window.scrollY||document.documentElement.scrollTop||0,n=Math.max(document.body&&document.body.scrollHeight||0,document.documentElement&&document.documentElement.scrollHeight||0);if(n<=0)return;let i=Math.min(100,Math.floor((o+window.innerHeight)/n*100));for(let a of t)i>=a&&!ft[a]&&(ft[a]=!0,l("scroll_depth",{depth:a}))}catch(o){}};r(),window.addEventListener("scroll",()=>{e||(e=setTimeout(()=>{e=null,r()},250))},{passive:!0})}function mo(){document.body&&document.body.addEventListener("submit",t=>{try{let e=t.target;if(!e||e.tagName!=="FORM"||e.querySelector('input[type="password"], input[name*="card"], input[name*="cpf"]'))return;let r="other",o=(e.className||"").toLowerCase(),n=(e.action||"").toLowerCase();e.querySelector('input[type="search"], input[name="q"], input[name="s"]')?r="search":/newsletter|subscribe|mailchimp/.test(o+n)?r="newsletter":/contact|contato/.test(o+n)&&(r="contact"),l("form_submit",{form_id:e.id||"",form_type:r})}catch(e){}},{capture:!0})}function ho(){let t=f();O=Date.now(),uo=setInterval(()=>{if(document.hidden)return;let e=Date.now(),r=Math.round((e-O)/1e3);O=e,r>0&&r<60&&l("engagement",{url:location.pathname,dwellSec:r})},t.engagementIntervalMs),document.addEventListener("visibilitychange",()=>{if(document.hidden){let e=Math.round((Date.now()-O)/1e3);e>0&&e<600&&l("engagement",{url:location.pathname,dwellSec:e})}O=Date.now()})}function go(t){let e=location.href,r=()=>{location.href!==e&&(e=location.href,Zt(t))};try{let o=history.pushState,n=history.replaceState;history.pushState=function(){o.apply(this,arguments),setTimeout(r,0)},history.replaceState=function(){n.apply(this,arguments),setTimeout(r,0)},window.addEventListener("popstate",r)}catch(o){}}function mt(){let t=M(),e=k(["Product"]);if(e.length>0){let n=e[0],i=Array.isArray(n.offers)?n.offers[0]:n.offers;return{sku:t?t.value:n.sku||n.mpn||n.gtin13||n.productID||null,skuSource:t?t.source:null,name:typeof n.name=="string"?n.name:null,price:i&&parseFloat(i.price||i.lowPrice)||null,currency:i?i.priceCurrency:null,brand:n.brand?typeof n.brand=="string"?n.brand:n.brand.name:null,category:n.category||null}}let r=n=>{let i=document.querySelector('meta[property="og:'+n+'"], meta[property="product:'+n+'"]');return i?i.getAttribute("content"):null},o=n=>{let i=document.querySelector('[itemprop="'+n+'"]');return i?i.getAttribute("content")||(i.textContent||"").trim():null};if(t||r("type")==="product"||r("price:amount")||o("name")){let n=o("price")||r("price:amount");return{sku:t?t.value:null,skuSource:t?t.source:null,name:o("name")||r("title")||document.title||null,price:n&&parseFloat(String(n).replace(",","."))||null,currency:o("priceCurrency")||r("price:currency")||null,brand:o("brand")||null,category:null}}return null}function Qt(){let t=k(["Order","Invoice"]);if(t.length>0){let o=t[0],n=o.totalPaymentDue?parseFloat(o.totalPaymentDue.price):parseFloat(o.price||o.total);return{orderId:o.orderNumber||o.confirmationNumber||o.identifier||null,revenue:Number.isFinite(n)?n:null,currency:o.totalPaymentDue&&o.totalPaymentDue.priceCurrency||o.priceCurrency||null,source:"jsonld"}}try{if(Array.isArray(window.dataLayer))for(let o=window.dataLayer.length-1;o>=0;o--){let n=window.dataLayer[o];if(n&&n.event==="purchase"&&n.ecommerce){let i=n.ecommerce;return{orderId:i.transaction_id||i.transactionId||null,revenue:parseFloat(i.value||i.revenue)||null,currency:i.currency||i.currencyCode||null,itemCount:(i.items||i.products||[]).length||null,source:"datalayer"}}}}catch(o){}let e=document.querySelector('meta[property="order:total"], meta[name="order-total"]');if(e&&e.content)return{orderId:null,revenue:parseFloat(e.content)||null,source:"meta"};let r=yo();return r||null}function yo(){try{let t=[".order-total","#order-total",".total-price",".order__total","[data-order-total]",".summary-total",".grand-total"];for(let e of t){let r=document.querySelector(e);if(r){let o=xo(r.textContent);if(o)return{orderId:wo(),revenue:o,source:"dom"}}}return null}catch(t){return null}}function wo(){try{let e=(document.body.innerText||"").match(/(?:pedido|order|n[º°o]\.?)\s*#?\s*([A-Z0-9-]{4,})/i);return e?e[1]:null}catch(t){return null}}function xo(t){if(!t)return null;let e=String(t).replace(/[^\d.,]/g,"");if(!e)return null;let r;e.indexOf(",")>e.indexOf(".")?r=e.replace(/\./g,"").replace(",","."):r=e.replace(/,/g,"");let o=parseFloat(r);return Number.isFinite(o)&&o>0?o:null}function te(){let t=k(["ItemList","CollectionPage"]);if(t.length===0)return null;let e=t[0],r=e.itemListElement||e.mainEntity&&e.mainEntity.itemListElement||[],o=[];for(let n of r.slice(0,50)){let i=n.item||n;i&&(i.sku||i.productID||i.name)&&o.push(i.sku||i.productID||i.name)}return o.length>0?{count:o.length,skus:o.slice(0,20)}:null}var ee=!1,G=[/\b(adicionar|adic\.?|colocar|incluir|jogar)\b.{0,30}\b(carrinho|sacola|sacolinha|bag)\b/i,/\bcomprar\b(?!\s+(em|por|sem))/i,/\bcomprar\s*$/i,/^add\s+to\s+(cart|bag)\b/i,/^buy\s+(now|it|this)\b/i,/^(sacolinha|carrinho|sacola)$/i],bo=[/^finalizar(\s+(compra|pedido|pagamento))?\b/i,/^(fechar|confirmar)\s+(compra|pedido|pagamento)\b/i,/^pagar(\s+(agora|pedido))?\b/i,/^(complete|place)\s+(purchase|order)\b/i,/^checkout$/i];function F(t,e){for(let r=0;r<t.length;r++)if(t[r].test(e))return!0;return!1}function oe(t){switch(t){case"pdp":{let e=mt();l("view_item",e||{sku:null});break}case"category":case"search":{let e=te();l("view_item_list",e||{count:0});break}case"cart":l("view_cart",{});break;case"checkout":l("begin_checkout",{});break;case"purchase":ko();break}}function ko(){let t=Qt();if(t&&t.orderId){let e="_mk_purch_"+t.orderId;try{if(sessionStorage.getItem(e)){m("purchase j\xE1 contado",t.orderId);return}sessionStorage.setItem(e,"1")}catch(r){}}else if(ee)return;ee=!0,l("purchase",t||{revenue:null,_note:"no_order_data_extracted"}),m("purchase emitido",t)}function re(){if(!document.body)return;let t=0;document.body.addEventListener("click",e=>{try{let r=Date.now();if(r-t<150)return;let o=e.target;for(let c=0;c<5&&o&&o!==document.body&&!(o.tagName==="BUTTON"||o.tagName==="A"||o.getAttribute&&o.getAttribute("role")==="button");c++)o=o.parentElement;if(!o)return;let n=o.tagName!=="A",i=(o.textContent||"").replace(/\s+/g," ").trim();if(!i||i.length>80)return;let a=!1;if((F([G[0]],i)||n&&F([G[1]],i)||n&&F([G[2]],i)||F(G.slice(3),i))&&(a=!0),a){t=r;let c=mt();l("add_to_cart",{via:"click",buttonText:i,sku:c?c.sku:null,price:c?c.price:null});return}n&&F(bo,i)&&(t=r,l("begin_checkout",{via:"click",buttonText:i}))}catch(r){}},{capture:!0,passive:!0})}var b=null,C=null,X=!1,I=null,ne={},ht=null,W=0,w={onReady:null,onClose:null,onAddToCart:null,onProductLoaded:null,onError:null,onInteraction:null,onGenerationComplete:null},Co={gregory:"698c7e791d3129430f15dddd"};function ae(t){return t?Co[String(t).toLowerCase()]||t:null}async function R(t,e){let r=f(),o=ae(t);e=String(e||"").trim();let n=r.apiUrl+"/availability/"+o+"?sku="+encodeURIComponent(e),i=await fetch(n);if(!i.ok)throw new Error("availability HTTP "+i.status);return i.json()}async function ce(t,e){e||(e=t,t="698c7e791d3129430f15dddd");try{return(await R(t,e)).available===!0}catch(r){return!1}}async function Y(t){if(t=t||{},X)return;let e=ae(t.projectId||t.projectid||t.store),r=String(t.identifier||t.sku||"").trim();if(!e||!r){console.error("[mk-sdk] open: projectId e identifier obrigatorios");return}let o=e+":"+r;if(ne[o]!==!0){try{if(!(await R(e,r)).available){alert("Produto nao disponivel para prova virtual.");return}}catch(n){alert("Produto nao encontrado ou indisponivel.");return}ne[o]=!0}I={projectId:e,identifier:r,width:t.width||430,height:t.height||800},le(),vo(I),X=!0,W=Date.now(),l("modal_opened",{projectId:e,identifier:r})}function yt(){X&&(_o(),X=!1,S("onClose"),l("modal_closed",{projectId:I&&I.projectId,identifier:I&&I.identifier}))}function vo(t){b=document.createElement("div"),b.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,.8);display:flex;align-items:center;justify-content:center;z-index:99999;";let e=document.createElement("div"),r=typeof t.width=="number"?t.width+"px":t.width,o=typeof t.height=="number"?t.height+"px":t.height;e.style.cssText="position:relative;width:"+r+";height:"+o+";max-width:100vw;max-height:100dvh;border-radius:12px;overflow:hidden;background:#fff;",C=document.createElement("iframe");let n=encodeURIComponent(t.identifier).replace(/\./g,"%2E");C.src=f().appUrl+"/"+t.projectId+"/"+n,C.style.cssText="width:100%;height:100%;border:none;",C.setAttribute("allow","camera *; microphone *"),C.setAttribute("allowfullscreen","true"),e.appendChild(C),b.appendChild(e),document.body.appendChild(b),m("try-on modal aberto",C.src)}function _o(){b&&b.parentNode&&b.parentNode.removeChild(b),b=null,C=null}var ie=!1;function se(){le()}function le(){ie||(ie=!0,window.addEventListener("message",t=>{let e=t.data;if(!e||e.source!=="mkfashion-app")return;let r=e.action,o=e.data||{};switch(r){case"close_request":yt();break;case"ready":S("onReady",o);break;case"product_loaded":S("onProductLoaded",o),l("product_loaded",gt(o));break;case"interaction":{S("onInteraction",o),o&&o.method&&(ht=o.method),l(So(o),gt(o));break}case"add_to_cart":l("add_to_cart",Object.assign({via:"tryon"},gt(o))),typeof w.onAddToCart=="function"?S("onAddToCart",o):Vt(o).catch(()=>{});break;case"generation_start":W=Date.now();break;case"generation_complete":S("onGenerationComplete",o),l("generation_complete",{method:o.method||ht||"unknown",durationMs:W?Date.now()-W:null,success:o.success!==!1,imageUrlPresent:!!o.imageUrl});break;case"generation_error":S("onError",o),l("generation_error",{method:ht||"unknown",error:o&&o.error});break}}))}function So(t){return t&&t.action,"interaction"}function gt(t){if(!t||typeof t!="object")return t;let e={};for(let r in t){if(r==="imageUrl"||r==="image"||r==="product"){r==="product"&&t[r]?(e.productSku=t[r].sku||null,e.productName=t[r].name||null):e[r+"Present"]=!!t[r];continue}e[r]=t[r]}return e}function S(t,e){if(typeof w[t]=="function")try{w[t](e)}catch(r){console.error("[mk-sdk]",r)}}function ue(t){w.onReady=t}function de(t){w.onClose=t}function pe(t){w.onAddToCart=t}function fe(t){w.onProductLoaded=t}function me(t){w.onError=t}function he(t){w.onInteraction=t}function ge(t){w.onGenerationComplete=t}var Eo=767,Ao=1024,Lo=/(adicionar\s*(à|a|ao)?\s*(sacola|carrinho|cesta|bolsa))|adicionar ao carrinho|add to (cart|bag)|comprar agora|^comprar$|finalizar compra|eu quero/i,Io=/continuar|como comprar|lista|desejos|favorito|looks|cupom/i;function ye(t){try{let e=t.getBoundingClientRect();if(e.width<=0||e.height<=0)return!1;let r=getComputedStyle(t);return r.display!=="none"&&r.visibility!=="hidden"&&r.opacity!=="0"}catch(e){return!1}}function Ro(t){if(!t)return!1;try{let e=document.querySelector(t);return!!e&&ye(e)}catch(e){return!1}}function Po(t){return(t.tagName==="INPUT"?t.value||"":t.textContent||"").replace(/\s+/g," ").trim()}function Bo(t){if(!t||typeof t!="object"||t.selector)return t;let e=!1;if(["mobile","tablet","desktop"].forEach(o=>{let n=t[o];n&&n.mkAnchor===1&&n.anchor&&typeof n.anchor=="object"&&(e=!0)}),!e)return t;let r={};return["mobile","tablet","desktop"].forEach(o=>{let n=t[o];if(n){if(n.selector){r[o]=n;return}if(n.mkAnchor===1&&n.anchor&&typeof n.anchor=="object"){let i=n.anchor[o]||n.anchor.desktop||n.anchor.mobile||n.anchor.tablet;i&&i.selector&&(r[o]=i)}}}),["bpMobile","bpTablet","breakpoint"].forEach(o=>{t[o]!=null&&(r[o]=t[o])}),r}function wt(t){if(!t||typeof t!="object")return null;if(t=Bo(t),t.selector)return t;let e=[["mobile",t.mobile],["tablet",t.tablet],["desktop",t.desktop]].filter(u=>u[1]&&u[1].selector);if(e.length===0)return null;if(e.length===1)return e[0][1];let r=e.filter(([,u])=>Ro(u.selector));if(r.length===1)return r[0][1];let o=window.innerWidth||1024,n=Number(t.bpMobile)||Number(t.breakpoint)||Eo,i=Number(t.bpTablet)||Ao,a=u=>(e.find(s=>s[0]===u)||[])[1],c=o<=n?["mobile","tablet","desktop"]:o<=i?["tablet","desktop","mobile"]:["desktop","tablet","mobile"];for(let u of c){let s=a(u);if(s)return s}return e[0][1]}function we(){let t=f(),e=wt(t&&t.anchor);if(e&&e.selector)try{let o=document.querySelector(e.selector);if(o)return{el:o,position:e.position||"afterend",mode:e.mode||"flow",style:e.style||"",align:e.align||"top-left",selector:e.selector}}catch(o){}let r=document.querySelectorAll('button, [role="button"], a.btn, a.button, input[type="submit"], input[type="button"]');for(let o of r){let n=Po(o);if(!(!n||n.length>40)&&!Io.test(n)&&Lo.test(n)&&ye(o))return{el:o,position:"afterend",mode:"flow",style:"",selector:null}}return null}var y="'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",xt={none:"0",sm:"4px",md:"8px",pill:"9999px"},bt={none:"0",sm:"4px",md:"8px",lg:"16px"},jo='<svg viewBox="0 0 17.5263 20.6862" fill="none" xmlns="http://www.w3.org/2000/svg" style="display:block;width:100%;height:100%"><g><path d="M8.49995 12.1862C10.1568 12.1862 11.5 10.8431 11.5 9.18622C11.5 7.52936 10.1568 6.18622 8.49995 6.18622C6.8431 6.18622 5.49995 7.52936 5.49995 9.18622C5.49995 10.8431 6.8431 12.1862 8.49995 12.1862Z" stroke="currentColor" shape-rendering="crispEdges"/><path d="M0.5 9.11152C0.5 6.56953 0.5 5.29894 1.1099 4.38664C1.375 3.9902 1.71424 3.65088 2.10821 3.38809C2.6945 2.9958 3.42899 2.85564 4.55351 2.80588C5.09013 2.80588 5.55183 2.39949 5.65687 1.87284C5.73715 1.48708 5.94572 1.14138 6.24735 0.894155C6.54898 0.646934 6.92516 0.51336 7.31231 0.516006H9.9734C10.7779 0.516006 11.4709 1.08412 11.6288 1.87284C11.7339 2.39949 12.1956 2.80588 12.7322 2.80588C13.8559 2.85564 12.9129 4.67413 13.5 5.06559C13.8949 5.32932 15.1484 3.80355 15.5 4.02647C16.1099 4.93876 16.7857 6.56953 16.7857 9.11152C16.7857 11.6535 16.7857 12.9233 16.1758 13.8364C15.9107 14.2328 15.5715 14.5722 15.1775 14.835C14.2647 15.4445 12.9936 15.4445 10.4522 15.4445H6.83351C4.29213 15.4445 3.02103 15.4445 2.10821 14.835C1.71446 14.5718 1.3755 14.2322 1.11071 13.8356C0.933802 13.5672 0.803519 13.2698 0.725557 12.9564" stroke="currentColor" stroke-linecap="round"/><path d="M12.676 0.607931C12.9446 -0.178095 14.0307 -0.2019 14.3491 0.536515L14.3761 0.60838L14.7385 1.66839C14.8216 1.91149 14.9559 2.13395 15.1322 2.32076C15.3086 2.50757 15.5229 2.65439 15.7608 2.75131L15.8583 2.78769L16.9183 3.14971C17.7044 3.41831 17.7282 4.50437 16.9902 4.82283L16.9183 4.84978L15.8583 5.21225C15.6151 5.29526 15.3926 5.42947 15.2057 5.60582C15.0188 5.78218 14.8719 5.99657 14.7749 6.23453L14.7385 6.33155L14.3765 7.39201C14.1079 8.17803 13.0219 8.20184 12.7039 7.46387L12.676 7.39201L12.314 6.332C12.231 6.08881 12.0968 5.86627 11.9204 5.67938C11.744 5.49249 11.5297 5.3456 11.2917 5.24863L11.1947 5.21225L10.1347 4.85022C9.34817 4.58163 9.32437 3.49557 10.0628 3.17756L10.1347 3.14971L11.1947 2.78769C11.4378 2.70462 11.6602 2.57039 11.847 2.39404C12.0339 2.21769 12.1807 2.00333 12.2776 1.76541L12.314 1.66839L12.676 0.607931Z" fill="currentColor"/></g></svg>',No='<svg viewBox="0 0 11.6122 12.7248" fill="none" xmlns="http://www.w3.org/2000/svg" style="display:block;width:12px;height:12px"><path d="M4.09055 2.01133C4.43939 0.9905 5.84989 0.959583 6.26347 1.91858L6.29847 2.01192L6.76922 3.38858C6.8771 3.7043 7.05144 3.99321 7.28047 4.23583C7.5095 4.47845 7.7879 4.66912 8.09689 4.795L8.22347 4.84225L9.60014 5.31242C10.621 5.66125 10.6519 7.07175 9.69347 7.48533L9.60014 7.52033L8.22347 7.99108C7.90764 8.09889 7.61862 8.2732 7.3759 8.50223C7.13318 8.73127 6.94241 9.0097 6.81647 9.31875L6.76922 9.44475L6.29905 10.822C5.95022 11.8428 4.53972 11.8737 4.12672 10.9153L4.09055 10.822L3.62039 9.44533C3.51258 9.12951 3.33827 8.84048 3.10924 8.59776C2.8802 8.35504 2.60177 8.16427 2.29272 8.03833L2.16672 7.99108L0.790054 7.52092C-0.231363 7.17208 -0.26228 5.76158 0.69672 5.34858L0.790054 5.31242L2.16672 4.84225C2.48244 4.73437 2.77135 4.56003 3.01397 4.331C3.25658 4.10197 3.44726 3.82357 3.57314 3.51458L3.62039 3.38858L4.09055 2.01133ZM9.86147 0C9.9706 0 10.0775 0.0306123 10.1701 0.0883584C10.2627 0.146104 10.3373 0.228668 10.3853 0.326667L10.4133 0.394917L10.6175 0.993417L11.2166 1.19758C11.3259 1.23474 11.4218 1.30353 11.492 1.39523C11.5623 1.48693 11.6037 1.59741 11.611 1.71268C11.6184 1.82795 11.5914 1.94281 11.5334 2.04271C11.4755 2.14261 11.3891 2.22305 11.2854 2.27383L11.2166 2.30183L10.6181 2.506L10.4139 3.10508C10.3767 3.21442 10.3078 3.31024 10.2161 3.38041C10.1244 3.45058 10.0139 3.49194 9.89859 3.49925C9.78333 3.50656 9.66849 3.47949 9.56863 3.42147C9.46876 3.36345 9.38837 3.27709 9.33764 3.17333L9.30964 3.10508L9.10547 2.50658L8.50639 2.30242C8.39702 2.26526 8.30115 2.19647 8.23092 2.10477C8.16069 2.01307 8.11926 1.90259 8.11189 1.78732C8.10452 1.67205 8.13153 1.55719 8.18951 1.45729C8.24749 1.35739 8.33381 1.27695 8.43755 1.22617L8.50639 1.19817L9.10489 0.994L9.30905 0.394917C9.34839 0.279665 9.42281 0.179613 9.52187 0.108791C9.62094 0.0379686 9.73969 -0.0000730808 9.86147 0Z" fill="currentColor"/></svg>';function p(t,e={}){let r=document.createElement(t);if(e.style&&(r.style.cssText=e.style),e.text!=null&&(r.textContent=e.text),e.html!=null&&(r.innerHTML=e.html),e.attrs)for(let o in e.attrs)r.setAttribute(o,e.attrs[o]);if(e.on)for(let o in e.on)r.addEventListener(o,e.on[o]);if(e.children)for(let o of e.children)o&&r.appendChild(o);return r}function Z(t){return p("span",{style:`width:24px;height:24px;padding:2px;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;color:${t};flex-shrink:0;`,html:jo})}function xe(t){return p("span",{style:`width:12px;height:12px;display:inline-flex;align-items:center;justify-content:center;color:${t};flex-shrink:0;`,html:No})}function Q(t){return t.borderWidth>0&&t.borderColor?`${t.borderWidth}px solid ${t.borderColor}`:"none"}function tt(){if(!document.getElementById("mk-jakarta-font"))try{document.head.appendChild(p("link",{attrs:{id:"mk-jakarta-font",rel:"stylesheet",href:"https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;600;700&display=swap"}}))}catch(t){}}function Uo(t){return t.subtext?p("span",{style:`display:flex;align-items:center;justify-content:center;padding:4px;background:${t.badgeBgColor};font-family:${y};font-weight:700;font-size:16px;text-transform:uppercase;color:${t.badgeTextColor};line-height:1;white-space:nowrap;`,text:t.subtext}):null}function be(t,e){tt();let r=p("span",{style:"display:inline-flex;align-items:center;gap:4px;",children:[Z(t.textColor),p("span",{text:t.text,style:`font-family:${y};font-weight:700;font-size:${t.fontSize}px;text-transform:uppercase;letter-spacing:2px;color:${t.textColor};white-space:nowrap;text-align:center;line-height:1;`})]});return p("button",{attrs:{type:"button"},style:`display:flex;align-items:center;justify-content:center;gap:8px;padding:8px;width:100%;max-width:238px;box-sizing:border-box;background:${t.bgColor};border:${Q(t)};border-radius:${t.borderRadiusPx};font-family:${y};cursor:pointer;transition:opacity 0.2s ease;line-height:1;-webkit-appearance:none;appearance:none;`,children:[r,Uo(t)],on:{mouseenter:o=>{o.currentTarget.style.opacity="0.85"},mouseleave:o=>{o.currentTarget.style.opacity="1"},click:()=>{try{e&&e()}catch(o){}}}})}function Oo(t){return t.subtext?p("span",{style:`display:flex;align-items:center;gap:4px;padding:4px;background:${t.badgeBgColor};font-family:${y};font-weight:600;font-size:10px;text-transform:uppercase;color:${t.badgeTextColor};line-height:1;white-space:nowrap;`,children:[xe(t.badgeTextColor),p("span",{text:t.subtext})]}):null}function Fo(t,e){return p("button",{attrs:{type:"button"},style:`display:flex;align-items:center;justify-content:center;gap:8px;padding:8px 12px 8px 8px;width:100%;margin-top:auto;box-sizing:border-box;background:${t.bgColor};border:${Q(t)};border-radius:${t.borderRadiusPx};filter:drop-shadow(0 0 6px rgba(0,0,0,0.08));font-family:${y};cursor:pointer;transition:opacity 0.2s ease;line-height:1;-webkit-appearance:none;appearance:none;`,children:[Z(t.textColor),p("span",{text:t.text,style:`font-family:${y};font-weight:700;font-size:${t.fontSize}px;color:${t.textColor};white-space:nowrap;line-height:1;`})],on:{mouseenter:r=>{r.currentTarget.style.opacity="0.85"},mouseleave:r=>{r.currentTarget.style.opacity="1"},click:()=>{try{e&&e()}catch(r){}}}})}function ke(t,e){tt();let r=p("div",{style:"display:flex;flex-direction:column;gap:4px;",children:[t.cardTitle&&p("p",{text:t.cardTitle,style:`margin:0;font-family:${y};font-weight:700;font-size:16px;letter-spacing:1px;text-transform:uppercase;color:${t.cardTitleColor};line-height:1.2;`}),t.cardDescription&&p("p",{html:t.cardDescription,style:`margin:0;font-family:${y};font-weight:400;font-size:12px;max-width:177px;line-height:1.2;color:${t.cardTextColor};`})]}),o=p("div",{style:"display:flex;flex-direction:column;justify-content:space-between;gap:16px;flex:1 1 0;min-width:0;",children:[r,t.cardFooter&&p("p",{text:t.cardFooter,style:`margin:0;font-family:${y};font-weight:400;font-size:10px;color:${t.cardTextColor};line-height:1.2;`})]}),n=p("div",{style:"display:flex;flex-direction:column;align-items:flex-end;flex:1 1 0;min-width:0;",children:[Oo(t),Fo(t,e)]}),i=p("div",{style:"display:flex;gap:16px;align-items:stretch;width:100%;flex:1;box-sizing:border-box;",children:[o,n]});return p("div",{style:`display:flex;flex-direction:column;align-items:flex-start;padding:12px;width:100%;max-width:402px;min-height:140px;box-sizing:border-box;background:${t.cardBgColor};border-radius:${t.cardBorderRadiusPx};font-family:${y};`,children:[i]})}var zo={style:"gregory-black",text:"Provar Virtualmente",fontSize:14,subtext:"",bgColor:"#1E1E1E",textColor:"#FFFFFF",badgeBgColor:"#C51A1B",badgeTextColor:"#FFFFFF",borderRadius:"md",borderColor:"#1E1E1E",borderWidth:0,cardTitle:"",cardDescription:"",cardFooter:"",cardBgColor:"#F6F6F6",cardTitleColor:"#1E1E1E",cardTextColor:"#717171",cardBorderRadius:"md"};async function kt(t,e){try{let r=await fetch(`${t}/projects/${e}`);if(!r.ok)throw new Error("HTTP "+r.status);let o=await r.json();return o&&o.project&&o.project.template&&o.project.template.tryOnButton||o&&o.template&&o.template.tryOnButton||null}catch(r){return null}}function Ct(t,e){let r=(e?t&&t.mobile:t&&t.desktop)||t&&t.desktop||t&&t.mobile||{},o={...zo,...r};return o.style==="gregory-card"&&e&&(o.style="gregory-black"),o.borderRadiusPx=xt[o.borderRadius]!=null?xt[o.borderRadius]:"0",o.cardBorderRadiusPx=bt[o.cardBorderRadius]!=null?bt[o.cardBorderRadius]:"0",o.fontSize=Number(o.fontSize)||14,o.borderWidth=Number(o.borderWidth)||0,o}var vt={"gregory-black":be,"gregory-card":ke},Ir=Object.keys(vt);function Ce(t,e){return(vt[t.style]||vt["gregory-black"])(t,e)}var Et="mk-tryon-button-host",et=null,_t=!1,St={},ve=!1,Tt=null;function _e(t,e){return Tt||(Tt=kt(t,e).catch(()=>null)),Tt}function qo(){if(ve)return;ve=!0;let t=null;try{window.addEventListener("resize",()=>{clearTimeout(t),t=setTimeout(()=>{et&&P("pdp")},200)})}catch(e){}}function At(){let t=document.getElementById(Et);if(t){if(typeof t.__mkCleanup=="function")try{t.__mkCleanup()}catch(e){}t.parentNode&&t.parentNode.removeChild(t)}et=null}var $o={IMG:1,INPUT:1,VIDEO:1,CANVAS:1,EMBED:1,OBJECT:1,IFRAME:1,BR:1,HR:1,SELECT:1,TEXTAREA:1,SVG:1};function Ko(t){switch(t){case"top-center":return"top:0;left:50%;transform:translateX(-50%);";case"top-right":return"top:0;right:0;";case"middle-left":return"top:50%;left:0;transform:translateY(-50%);";case"center":return"top:50%;left:50%;transform:translate(-50%,-50%);";case"middle-right":return"top:50%;right:0;transform:translateY(-50%);";case"bottom-left":return"bottom:0;left:0;";case"bottom-center":return"bottom:0;left:50%;transform:translateX(-50%);";case"bottom-right":return"bottom:0;right:0;";case"top-left":default:return"top:0;left:0;"}}function Ho(t,e,r){let n=!$o[t.tagName]?t:t.parentElement||document.body;try{getComputedStyle(n).position==="static"&&(n.style.position="relative")}catch(s){}if(n===t){e.style.cssText="position:absolute;z-index:2147483000;"+Ko(r),t.appendChild(e);return}e.style.cssText="position:absolute;z-index:2147483000;",n.appendChild(e);let i=()=>{try{let s=t.getBoundingClientRect(),x=n.getBoundingClientRect(),h=e.offsetWidth,d=e.offsetHeight,v=s.top-x.top+n.scrollTop,T=s.left-x.left+n.scrollLeft,g=r||"top-left",D=v,_=T;g.indexOf("bottom")===0?D=v+s.height-d:(g.indexOf("middle")===0||g==="center")&&(D=v+(s.height-d)/2),g.indexOf("right")>=0?_=T+s.width-h:g.indexOf("center")>=0&&(_=T+(s.width-h)/2),e.style.top=D+"px",e.style.left=_+"px"}catch(s){}};i();let a=()=>i();window.addEventListener("resize",a);let c=setTimeout(i,600),u=setTimeout(i,1500);e.__mkCleanup=()=>{window.removeEventListener("resize",a),clearTimeout(c),clearTimeout(u)}}function Jo(t,e,r){try{return t.insertAdjacentElement(r||"afterend",e),!0}catch(o){try{return t.parentNode.insertBefore(e,t.nextSibling),!0}catch(n){return!1}}}async function P(t){let e=f();if(t!=="pdp"){At();return}if(!e.projectId)return;if(!e.anchor){let u=await _e(e.apiUrl,e.projectId);u&&u.anchor&&(e.anchor=u.anchor)}if(_t)return;let r=M(),o=r&&r.value,n=!!e.forceButton,i=wt(e.anchor),a=[o||"demo",i?[i.selector,i.position,i.mode,i.align,i.style].join("~"):"heuristic"].join("|"),c=document.getElementById(Et);if(!(c&&et===a)){if(c&&At(),!o&&!n){m("auto-mount: SKU n\xE3o resolvido na PDP");return}_t=!0;try{let u=n;if(n||(St[o]||(St[o]=R(e.projectId,o).then(E=>!!(E&&E.available)).catch(()=>!1)),u=await St[o]),!u){m("auto-mount: produto sem try-on",o);return}let s=await _e(e.apiUrl,e.projectId),x=window.matchMedia("(max-width: 767px)").matches,h=Ct(s,x),d=we(),v=d&&d.mode||"flow",T=Ce(h,()=>{let E=M();Y({projectId:e.projectId,identifier:E&&E.value||o||""})}),g=document.createElement("div");g.id=Et,g.attachShadow({mode:"open"}).appendChild(T);let _=!1;if(d&&d.el&&d.el.parentNode&&(v==="overlay"?(Ho(d.el,g,d.align),_=!0):(g.style.cssText="display:contents;",_=Jo(d.el,g,d.position))),_||(g.style.cssText="position:fixed;left:16px;bottom:16px;z-index:2147483000;",document.body.appendChild(g)),d&&d.style)try{T.style.cssText+=";"+d.style}catch(E){}et=a,qo(),m("auto-mount: bot\xE3o injetado",{style:h.style,sku:o,anchorFound:!!d,position:d&&d.position,mode:v,forced:n}),l("button_rendered",{style:h.style,sku:o||null,skuSource:r&&r.source,anchorFound:!!d,position:d?d.position:null,mode:v,forced:n})}finally{_t=!1}}}function Se(){try{let t=f(),e={anchor:t.anchor,forceButton:t.forceButton};window.addEventListener("message",r=>{if(r.source!==window)return;let o=r.data;!o||!o.__mkCmd||(o.__mkCmd==="remount"||o.__mkCmd==="applyRecipe"?(t.anchor=o.anchor||null,t.forceButton=!0,P("pdp")):o.__mkCmd==="cancelPreview"&&(t.anchor=e.anchor,t.forceButton=e.forceButton,At(),P("pdp")))})}catch(t){}}(function(){"use strict";try{let r=function(){try{Ft(),Se(),se(),e.autoTrack!==!1&&(Yt((n,i)=>{oe(n,i),P(n)}),re()),m("mk-sdk iniciado",{projectId:e.projectId,collectorUrl:e.collectorUrl})}catch(n){e.debug&&console.error("[mk-sdk] init erro",n)}},e=rt();document.readyState==="loading"?document.addEventListener("DOMContentLoaded",r):r();let o={open:Y,close:yt,isAvailable:ce,getAvailability:R,onReady:ue,onClose:de,onAddToCart:pe,onProductLoaded:fe,onError:me,onInteraction:he,onGenerationComplete:ge,_version:"0.1.0",_isMkSdk:!0};typeof window!="undefined"&&(window.mk=o)}catch(e){typeof console!="undefined"&&console.error("[mk-sdk] boot fatal",e)}})();})();
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "mk-sdk-git",
3
+ "version": "0.1.0",
4
+ "description": "SDK de tracking de e-commerce + try-on da MetaKosmos (core tracker, roda em todas as páginas)",
5
+ "main": "dist/mk-sdk.js",
6
+ "files": [
7
+ "dist",
8
+ "src",
9
+ "README.md"
10
+ ],
11
+ "scripts": {
12
+ "build": "node esbuild.config.js",
13
+ "build:watch": "node esbuild.config.js --watch",
14
+ "build:ext": "node esbuild.config.js && node -e \"require('fs').copyFileSync('dist/mk-sdk.js','extension/mk-sdk.js'); console.log('bundle -> extension/mk-sdk.js')\"",
15
+ "size": "gzip -c dist/mk-sdk.js | wc -c"
16
+ },
17
+ "keywords": [
18
+ "analytics",
19
+ "ecommerce",
20
+ "tracking",
21
+ "try-on",
22
+ "metakosmos"
23
+ ],
24
+ "author": "metaKosmos",
25
+ "license": "MIT",
26
+ "devDependencies": {
27
+ "esbuild": "^0.20.0",
28
+ "playwright": "^1.60.0"
29
+ }
30
+ }
@@ -0,0 +1,159 @@
1
+ // autoTrack.js — captura automática de comportamento (pageview, click, scroll,
2
+ // form, engagement) + SPA navigation. Independente de plataforma.
3
+
4
+ import { getConfig } from './config.js';
5
+ import { track, setSiteContext } from './transport.js';
6
+ import { detectPageType, buildSiteContext } from './pageContext.js';
7
+
8
+ let scrollSeen = {};
9
+ let engagementTimer = null;
10
+ let engagementLastTick = 0;
11
+ let started = false;
12
+
13
+ /**
14
+ * Inicia toda a captura automática. Idempotente.
15
+ */
16
+ export function startAutoTrack(onPageView) {
17
+ if (started) return;
18
+ started = true;
19
+
20
+ trackPageview(onPageView);
21
+ initClickTracking();
22
+ initScrollTracking();
23
+ initFormTracking();
24
+ initEngagementTracking();
25
+ initSpaNavigation(onPageView);
26
+ }
27
+
28
+ function trackPageview(onPageView) {
29
+ scrollSeen = {};
30
+ const pageType = detectPageType();
31
+ const ctx = buildSiteContext(pageType);
32
+ setSiteContext(ctx);
33
+ track('view', {
34
+ url: location.href,
35
+ pathname: location.pathname,
36
+ referrer: document.referrer || null,
37
+ title: document.title || null,
38
+ pageType: pageType
39
+ });
40
+ // Callback pra módulo de ecommerce reagir ao tipo de página
41
+ if (typeof onPageView === 'function') {
42
+ try { onPageView(pageType, ctx); } catch (_) {}
43
+ }
44
+ }
45
+
46
+ function initClickTracking() {
47
+ if (!document.body) return;
48
+ const INTERACTIVE = { A: 1, BUTTON: 1, INPUT: 1, SELECT: 1, TEXTAREA: 1 };
49
+ let lastClick = 0;
50
+ document.body.addEventListener('click', (e) => {
51
+ try {
52
+ const now = Date.now();
53
+ if (now - lastClick < 100) return;
54
+ lastClick = now;
55
+ let el = e.target;
56
+ for (let i = 0; i < 5 && el && el !== document.body; i++) {
57
+ if (INTERACTIVE[el.tagName] || (el.getAttribute && el.getAttribute('role') === 'button')) break;
58
+ el = el.parentElement;
59
+ }
60
+ if (!el) return;
61
+ if (!INTERACTIVE[el.tagName] && !(el.getAttribute && el.getAttribute('role') === 'button')) return;
62
+
63
+ const data = { tag: el.tagName };
64
+ const t = el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' ? el.value : el.textContent;
65
+ data.text = (t || '').replace(/\s+/g, ' ').trim().substring(0, 100);
66
+ if (el.href) data.href = String(el.href).substring(0, 500);
67
+ if (el.id) data.id = el.id;
68
+ if (el.className && typeof el.className === 'string') data.classes = el.className.trim().substring(0, 200);
69
+ track('click', data);
70
+ } catch (_) {}
71
+ }, { capture: true, passive: true });
72
+ }
73
+
74
+ function initScrollTracking() {
75
+ const TH = [25, 50, 75, 100];
76
+ let scrollTimer = null;
77
+ const check = () => {
78
+ try {
79
+ const sy = window.scrollY || document.documentElement.scrollTop || 0;
80
+ const dh = Math.max(
81
+ (document.body && document.body.scrollHeight) || 0,
82
+ (document.documentElement && document.documentElement.scrollHeight) || 0
83
+ );
84
+ if (dh <= 0) return;
85
+ const pct = Math.min(100, Math.floor(((sy + window.innerHeight) / dh) * 100));
86
+ for (const t of TH) {
87
+ if (pct >= t && !scrollSeen[t]) {
88
+ scrollSeen[t] = true;
89
+ track('scroll_depth', { depth: t });
90
+ }
91
+ }
92
+ } catch (_) {}
93
+ };
94
+ check();
95
+ window.addEventListener('scroll', () => {
96
+ if (scrollTimer) return;
97
+ scrollTimer = setTimeout(() => { scrollTimer = null; check(); }, 250);
98
+ }, { passive: true });
99
+ }
100
+
101
+ function initFormTracking() {
102
+ if (!document.body) return;
103
+ document.body.addEventListener('submit', (e) => {
104
+ try {
105
+ const f = e.target;
106
+ if (!f || f.tagName !== 'FORM') return;
107
+ // Skip forms de checkout (PII). Detecta por classe/campos sensíveis.
108
+ if (f.querySelector('input[type="password"], input[name*="card"], input[name*="cpf"]')) return;
109
+ let ft = 'other';
110
+ const cls = (f.className || '').toLowerCase();
111
+ const act = (f.action || '').toLowerCase();
112
+ if (f.querySelector('input[type="search"], input[name="q"], input[name="s"]')) ft = 'search';
113
+ else if (/newsletter|subscribe|mailchimp/.test(cls + act)) ft = 'newsletter';
114
+ else if (/contact|contato/.test(cls + act)) ft = 'contact';
115
+ track('form_submit', { form_id: f.id || '', form_type: ft });
116
+ } catch (_) {}
117
+ }, { capture: true });
118
+ }
119
+
120
+ function initEngagementTracking() {
121
+ const cfg = getConfig();
122
+ engagementLastTick = Date.now();
123
+ engagementTimer = setInterval(() => {
124
+ if (document.hidden) return;
125
+ const now = Date.now();
126
+ const elapsed = Math.round((now - engagementLastTick) / 1000);
127
+ engagementLastTick = now;
128
+ if (elapsed > 0 && elapsed < 60) {
129
+ track('engagement', { url: location.pathname, dwellSec: elapsed });
130
+ }
131
+ }, cfg.engagementIntervalMs);
132
+
133
+ document.addEventListener('visibilitychange', () => {
134
+ if (document.hidden) {
135
+ const elapsed = Math.round((Date.now() - engagementLastTick) / 1000);
136
+ if (elapsed > 0 && elapsed < 600) {
137
+ track('engagement', { url: location.pathname, dwellSec: elapsed });
138
+ }
139
+ }
140
+ engagementLastTick = Date.now();
141
+ });
142
+ }
143
+
144
+ function initSpaNavigation(onPageView) {
145
+ let lastUrl = location.href;
146
+ const onChange = () => {
147
+ if (location.href !== lastUrl) {
148
+ lastUrl = location.href;
149
+ trackPageview(onPageView); // re-detecta pageType na nova rota
150
+ }
151
+ };
152
+ try {
153
+ const origPush = history.pushState;
154
+ const origReplace = history.replaceState;
155
+ history.pushState = function () { origPush.apply(this, arguments); setTimeout(onChange, 0); };
156
+ history.replaceState = function () { origReplace.apply(this, arguments); setTimeout(onChange, 0); };
157
+ window.addEventListener('popstate', onChange);
158
+ } catch (_) {}
159
+ }
@@ -0,0 +1,84 @@
1
+ // config.js — configuração resolvida do script tag + defaults.
2
+
3
+ const PROD = {
4
+ collectorUrl: 'https://collector.metakosmos.com.br',
5
+ appUrl: 'https://mkfashion.mk3dlabs.com/visualizer',
6
+ apiUrl: 'https://mkfashion-new-api.mk3dlabs.com'
7
+ };
8
+
9
+ // DEV — sobrescreve via data-mk-collector no script tag, ou aqui em testes.
10
+ const DEV_OVERRIDE = {
11
+ // collectorUrl: 'http://localhost:3030'
12
+ };
13
+
14
+ let _config = null;
15
+
16
+ /**
17
+ * Lê config do <script data-mk-project="..." data-mk-collector="..."> que
18
+ * carregou a SDK. Resolve uma única vez.
19
+ */
20
+ export function resolveConfig() {
21
+ if (_config) return _config;
22
+
23
+ let script = null;
24
+ try {
25
+ script = document.currentScript ||
26
+ document.querySelector('script[data-mk-project]') ||
27
+ document.querySelector('script[src*="mk-sdk"]') ||
28
+ document.querySelector('script[src*="mk-pixel"]'); // compat: nome antigo do bundle
29
+ } catch (_) {}
30
+
31
+ const attr = (name) => {
32
+ try { return script && script.getAttribute(name); } catch (_) { return null; }
33
+ };
34
+
35
+ // projectId pode vir de data-mk-project, data-mk-client, ou window.__MK
36
+ const projectId = attr('data-mk-project') || attr('data-mk-client') ||
37
+ (window.__MK && (window.__MK.projectId || window.__MK.clientSlug)) || null;
38
+
39
+ // product identifica QUAL produto MetaKosmos roda nesta página (multi-produto).
40
+ // Hoje só existe 'mk-fashion'; no futuro 'mk-beauty', 'mk-3d', etc. Vai no
41
+ // payload de cada batch pra o collector/dashboard segmentar por produto.
42
+ const product = attr('data-mk-product') ||
43
+ (window.__MK && window.__MK.product) || 'mk-fashion';
44
+
45
+ // collectorUrl: data-attr > window.__MK > dev override > prod
46
+ const collectorUrl = attr('data-mk-collector') ||
47
+ (window.__MK && window.__MK.collectorUrl) ||
48
+ DEV_OVERRIDE.collectorUrl ||
49
+ PROD.collectorUrl;
50
+
51
+ _config = {
52
+ projectId,
53
+ product,
54
+ collectorUrl,
55
+ appUrl: (window.__MK && window.__MK.appUrl) || PROD.appUrl,
56
+ apiUrl: (window.__MK && window.__MK.apiUrl) || PROD.apiUrl,
57
+ debug: !!(attr('data-mk-debug') !== null || (window.__MK && window.__MK.debug) || /[?&]mkdebug\b/.test(location.search)),
58
+ // observe: emite cada evento via window.postMessage (consumido pela extensão de QA).
59
+ // Desligado em produção (script puro) — só liga via window.__MK.observe.
60
+ observe: !!(window.__MK && window.__MK.observe),
61
+ // forceButton: injeta o botão mesmo sem checar disponibilidade (modo demo/QA).
62
+ forceButton: !!(window.__MK && window.__MK.forceButton),
63
+ // anchor: posição customizada do botão { selector, position } (receita / picker).
64
+ anchor: (window.__MK && window.__MK.anchor) || null,
65
+ // cartRedirect: após adicionar ao carrinho pelo provador, leva o usuário ao /cart (default: sim).
66
+ cartRedirect: !(window.__MK && window.__MK.cartRedirect === false),
67
+ autoTrack: attr('data-mk-no-autotrack') === null, // autotrack ligado por padrão
68
+ batchIntervalMs: 2000,
69
+ batchMaxSize: 20,
70
+ engagementIntervalMs: 15000
71
+ };
72
+ return _config;
73
+ }
74
+
75
+ export function getConfig() {
76
+ return _config || resolveConfig();
77
+ }
78
+
79
+ export function log(...args) {
80
+ const c = getConfig();
81
+ if (c && c.debug && typeof console !== 'undefined') {
82
+ console.log('[mk-sdk]', ...args);
83
+ }
84
+ }
@@ -0,0 +1,57 @@
1
+ // identity.js — visitorId (persistente) + sessionId (por aba). Cookieless.
2
+
3
+ const VID_KEY = '_mk_vid';
4
+ const SID_KEY = '_mk_sid';
5
+
6
+ let _vid = null;
7
+ let _sid = null;
8
+
9
+ function uuid() {
10
+ if (typeof crypto !== 'undefined' && crypto.randomUUID) return crypto.randomUUID();
11
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
12
+ const r = (Math.random() * 16) | 0;
13
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
14
+ return v.toString(16);
15
+ });
16
+ }
17
+
18
+ export function getVisitorId() {
19
+ if (_vid) return _vid;
20
+ try {
21
+ let v = localStorage.getItem(VID_KEY);
22
+ if (!v) {
23
+ v = 'v_' + uuid();
24
+ localStorage.setItem(VID_KEY, v);
25
+ }
26
+ _vid = v;
27
+ return v;
28
+ } catch (_) {
29
+ _vid = 'v_' + uuid();
30
+ return _vid;
31
+ }
32
+ }
33
+
34
+ export function getSessionId() {
35
+ if (_sid) return _sid;
36
+ try {
37
+ let s = sessionStorage.getItem(SID_KEY);
38
+ if (!s) {
39
+ s = 's_' + uuid();
40
+ sessionStorage.setItem(SID_KEY, s);
41
+ }
42
+ _sid = s;
43
+ return s;
44
+ } catch (_) {
45
+ _sid = 's_' + uuid();
46
+ return _sid;
47
+ }
48
+ }
49
+
50
+ export function resetIdentity() {
51
+ try {
52
+ localStorage.removeItem(VID_KEY);
53
+ sessionStorage.removeItem(SID_KEY);
54
+ } catch (_) {}
55
+ _vid = null;
56
+ _sid = null;
57
+ }
@@ -0,0 +1,83 @@
1
+ // pageContext.js — classifica o tipo de página por sinais nativos.
2
+
3
+ import { readJsonLd } from '../ecommerce/jsonld.js';
4
+ import { detectPlatformId } from '../platforms/index.js';
5
+
6
+ const PURCHASE_URL = /\/(thank[_-]?you|orders?\/|pedido[_-]?(confirmado|realizado|finalizado|sucesso)|sucesso|order[_-]?confirmation|compra[_-]?(finalizada|concluida)|orderplaced)/i;
7
+ const CHECKOUT_URL = /\/checkout/i;
8
+ const CART_URL = /\/(cart|carrinho|sacola|bag)(\/|$|\?|#)/i;
9
+ const PDP_URL = /\/(products?|produtos?|p)\//i;
10
+ const CATEGORY_URL = /\/(collections?|categoria|categorias|c|departamento)\//i;
11
+ const SEARCH_URL = /\/(search|busca|s)(\/|\?)/i;
12
+
13
+ /**
14
+ * Detecta o tipo de página. Cascata: override > JSON-LD > URL patterns.
15
+ * Retorna: home | category | search | pdp | cart | checkout | purchase | other
16
+ */
17
+ export function detectPageType() {
18
+ // 1. Override explícito do cliente
19
+ try {
20
+ if (window.__mkPageType) return window.__mkPageType;
21
+ } catch (_) {}
22
+
23
+ // 2. JSON-LD @type
24
+ try {
25
+ const ld = readJsonLd();
26
+ for (const item of ld) {
27
+ const types = Array.isArray(item['@type']) ? item['@type'] : [item['@type']];
28
+ if (types.includes('Order') || types.includes('Invoice')) return 'purchase';
29
+ if (types.includes('Product')) return 'pdp';
30
+ if (types.includes('SearchResultsPage')) return 'search';
31
+ if (types.includes('CollectionPage') || types.includes('ItemList')) return 'category';
32
+ }
33
+ } catch (_) {}
34
+
35
+ // 3. URL patterns
36
+ const p = (location.pathname || '').toLowerCase();
37
+ if (p === '/' || p === '' || p === '/home' || p === '/index.html') return 'home';
38
+ if (PURCHASE_URL.test(p)) return 'purchase';
39
+ if (CHECKOUT_URL.test(p)) return 'checkout';
40
+ if (CART_URL.test(p)) return 'cart';
41
+ if (PDP_URL.test(p)) return 'pdp';
42
+ if (CATEGORY_URL.test(p)) return 'category';
43
+ if (SEARCH_URL.test(p)) return 'search';
44
+ return 'other';
45
+ }
46
+
47
+ /**
48
+ * Monta o contexto do site enviado em cada batch.
49
+ */
50
+ export function buildSiteContext(pageType) {
51
+ let utm = null;
52
+ try {
53
+ const params = new URLSearchParams(location.search);
54
+ const keys = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];
55
+ const out = {};
56
+ for (const k of keys) {
57
+ const v = params.get(k);
58
+ if (v) out[k.replace('utm_', '')] = v;
59
+ }
60
+ if (Object.keys(out).length) utm = out;
61
+ } catch (_) {}
62
+
63
+ return {
64
+ url: location.href,
65
+ pathname: location.pathname,
66
+ referrer: document.referrer || null,
67
+ title: document.title || null,
68
+ pageType: pageType,
69
+ utm: utm,
70
+ userAgent: navigator.userAgent,
71
+ language: navigator.language,
72
+ viewport: window.innerWidth + 'x' + window.innerHeight,
73
+ platform: detectPlatform()
74
+ };
75
+ }
76
+
77
+ /**
78
+ * Detecta a plataforma e-commerce. Delega ao registry de plataformas
79
+ * (src/platforms/) — toda a lógica de detecção por plataforma vive lá.
80
+ */
81
+ export function detectPlatform() {
82
+ return detectPlatformId();
83
+ }