@cnv-vn/track 0.2.0-beta.4 → 0.2.0-beta.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cnv-vn/track",
3
- "version": "0.2.0-beta.4",
3
+ "version": "0.2.0-beta.6",
4
4
  "description": "CNV Tracking SDK — lightweight, async-first web analytics tracker (<20KB gzipped).",
5
5
  "keywords": [
6
6
  "analytics",
@@ -14,14 +14,6 @@
14
14
  ],
15
15
  "license": "UNLICENSED",
16
16
  "author": "CNV <dev@cnv.vn>",
17
- "homepage": "https://internal.192168173.com/cnv/common/cnv-tracking",
18
- "repository": {
19
- "type": "git",
20
- "url": "git+https://internal.192168173.com/cnv/common/cnv-tracking.git"
21
- },
22
- "bugs": {
23
- "url": "https://internal.192168173.com/cnv/common/cnv-tracking/-/issues"
24
- },
25
17
  "type": "module",
26
18
  "main": "./dist/cnv-track.umd.cjs",
27
19
  "module": "./dist/cnv-track.esm.js",
@@ -1,6 +0,0 @@
1
- /*!
2
- * @cnv-vn/track v0.2.0-beta.4
3
- * (c) 2026 CNV
4
- * Released under the UNLICENSED license.
5
- */
6
- const t=["pdf","doc","docx","xls","xlsx","ppt","pptx","txt","csv","rtf","zip","rar","7z","tar","gz","mp3","mp4","mov","wav","avi","mkv","dmg","exe","pkg","apk","msi","svg"];function n(t){return!!t&&"object"==typeof t&&1===t.nodeType&&"A"===t.tagName}function e(t){const n=t.lastIndexOf("/");return-1===n?t:t.slice(n+1)}function r(t){var n,e,r;let o=(null!==(n=t.textContent)&&void 0!==n?n:"").trim();return o||(o=(null!==(e=t.getAttribute("aria-label"))&&void 0!==e?e:"").trim()),o||(o=(null!==(r=t.getAttribute("title"))&&void 0!==r?r:"").trim()),o.length>200?o.slice(0,200):o}const o=200;function i(t){let n="";try{n=(t.textContent||"").replace(/\s+/g," ").trim(),n||(n=(t.getAttribute("aria-label")||"").trim()),n||(n=(t.getAttribute("title")||"").trim()),n=n.normalize("NFC")}catch(t){return""}return n.length>o?n.slice(0,o):n}function c(t){const n=!1!==t.caseInsensitive;if("regex"===t.mode)return{mode:"regex",needle:t.value,ci:n,re:m(t.value,n)};const e=t.value.normalize("NFC");return{mode:t.mode,needle:n?e.toLowerCase():e,ci:n,re:null}}function u(t,n){try{return t.matches(n)}catch(t){return!1}}function l(t){try{if("A"===t.tagName){const n=t.getAttribute("href");return n?p(n):null}const n=t.getAttribute("formaction");if(n)return p(n);const e=t.getAttribute("data-href");if(e)return p(e);const r=t.closest("form");if(r){const t=r.getAttribute("action");if(t)return p(t)}return null}catch(t){return null}}function s(t){return"regex"===t.mode?{mode:"regex",needle:t.value,re:m(t.value,!0)}:{mode:t.mode,needle:t.value.toLowerCase(),re:null}}function a(t){if("startsWith"===t.mode)return{mode:"startsWith",needle:t.value,re:null};const n="glob"===t.mode?"^"+t.value.replace(/[.+^${}()|[\]\\?]/g,"\\$&").replace(/\*/g,".*")+"$":t.value;return{mode:t.mode,needle:t.value,re:m(n,!1)}}function f(t,n){return"startsWith"===t.mode?0===n.indexOf(t.needle):!t.re||b(t.re,n)}const d=/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,h=/\+?\d[\d\s().-]{7,}\d/g;function y(t){if(!t)return t;try{return t.replace(d,"[email]").replace(h,"[phone]")}catch(n){return t}}function v(t){return!!t&&"object"==typeof t&&1===t.nodeType}function p(t){try{return new URL(t,location.href).href}catch(n){return t}}function m(t,n){try{return!t||t.length>1e3?null:new RegExp(t,n?"i":"")}catch(t){return null}}function b(t,n){try{return t.test(n)}catch(t){return!1}}function g(t,n){if("undefined"==typeof document)return()=>{};const e=(t=>{const n=t.globalThrottle||{},e=[],r=t.rules||[];for(let t=0;t<r.length;t++){const o=r[t];if(!o||!1===o.enabled)continue;if(!o.match||!o.event)continue;const i=o.match,u=o.throttle||{};e.push({rule:o,elementSpec:w(o),selector:i.selector||null,text:i.text?c(i.text):null,dest:i.destinationUrl?s(i.destinationUrl):null,urlScope:o.urlScope?a(o.urlScope):null,dedupeWindowMs:S(u.dedupeWindowMs,S(n.dedupeWindowMs,500)),maxPerPageview:S(u.maxPerPageview,S(n.maxPerPageview,1/0)),samplingRate:A(S(u.samplingRate,S(n.samplingRate,1)))})}return e.sort((t,n)=>(t.rule.priority||0)-(n.rule.priority||0)),e})(n);if(0===e.length)return()=>{};const r=new WeakMap;let o=0;const i=t=>{let n=r.get(t);return void 0===n&&(n=++o,r.set(t,n)),String(n)},u=new Map,l=new Map;let d=O();function h(n){try{if(0!==n.button)return;const r=O();r!==d&&(d=r,l.clear(),u.clear());const o=(t=>{const n=[];try{const e="function"==typeof t.composedPath?t.composedPath():[];if(e&&e.length>0){for(const t of e)v(t)&&n.push(t);return n}let r=t.target;for(;r;)v(r)&&n.push(r),r=r.parentNode}catch(t){}return n})(n);if(0===o.length)return;const c=(()=>{try{return"undefined"!=typeof location?location.pathname+location.search:""}catch(t){return""}})();for(let r=0;r<e.length;r++){const s=e[r];if(s.urlScope&&!f(s.urlScope,c))continue;let a=null;for(let t=0;t<o.length;t++)if(x(s,o[t])){a=o[t];break}if(!a)continue;const d=s.rule.id;if((l.get(d)||0)>=s.maxPerPageview)return;const h=d+"#"+i(a),y=Date.now(),v=u.get(h);if(void 0!==v&&y-v<s.dedupeWindowMs)return;if(s.samplingRate<1&&Math.random()>=s.samplingRate)return;u.set(h,y),l.set(d,(l.get(d)||0)+1);const p=j(s.rule,a,n);return void k(()=>t.track("Clicked",p))}}catch(t){}}try{document.addEventListener("click",h,!0)}catch(t){return()=>{}}return()=>{try{document.removeEventListener("click",h,!0)}catch(t){}u.clear(),l.clear()}}function w(t){const n=t.match;return n.element?n.element:n.selector||n.id||n.dataAttr||n.classes&&n.classes.length>0||n.destinationUrl?"any":void 0}function x(t,n){if(!((t,n)=>{if(!n)return(t=>{const n=t.tagName;if("BUTTON"===n||"A"===n)return!0;if("INPUT"===n){const n=(t.getAttribute("type")||"").toLowerCase();return"submit"===n||"button"===n||"reset"===n}return"button"===t.getAttribute("role")})(t);if("any"===n)return!0;if("button"===n){const n=t.tagName;if("BUTTON"===n)return!0;if("INPUT"===n){const n=(t.getAttribute("type")||"").toLowerCase();return"submit"===n||"button"===n||"reset"===n}return"button"===t.getAttribute("role")}return"link"===n?"A"===t.tagName:u(t,n)})(n,t.elementSpec))return!1;const e=t.rule.match;return!(t.selector&&!u(n,t.selector)||void 0!==e.id&&!((t,n)=>t.id===n)(n,e.id)||e.classes&&e.classes.length>0&&!((t,n)=>{try{for(let e=0;e<n.length;e++)if(!t.classList.contains(n[e]))return!1;return!0}catch(t){return!1}})(n,e.classes)||e.dataAttr&&!((t,n,e)=>{try{return!!t.hasAttribute(n)&&(void 0===e||t.getAttribute(n)===e)}catch(t){return!1}})(n,e.dataAttr.name,e.dataAttr.value)||t.text&&!((t,n)=>{const e=i(t);if("regex"===n.mode)return!!n.re&&b(n.re,e);const r=n.ci?e.toLowerCase():e;return"exact"===n.mode?r===n.needle:"startsWith"===n.mode?0===r.indexOf(n.needle):-1!==r.indexOf(n.needle)})(n,t.text)||t.dest&&!((t,n)=>{const e=l(t);if(!e)return!1;if("regex"===n.mode)return!!n.re&&b(n.re,e);if("domain"===n.mode)try{return new URL(e).host.toLowerCase()===n.needle}catch(t){return!1}const r=e.toLowerCase();return"exact"===n.mode?r===n.needle:"startsWith"===n.mode?0===r.indexOf(n.needle):-1!==r.indexOf(n.needle)})(n,t.dest))}function j(t,n,e){const r={},c=t.event.staticProps;if(c)for(const t of Object.keys(c))r[t]=c[t];const u=t.capture;if(u)try{if(u.text){const t=y(i(n));t&&(r.text=t)}if(u.href){const t=l(n);t&&(r.href=t)}if(u.elementId&&n.id&&(r.element_id=n.id),u.classes&&(r.element_classes=Array.from(n.classList)),u.dataAttrs&&u.dataAttrs.length>0)for(let t=0;t<u.dataAttrs.length;t++){const e=u.dataAttrs[t],o=n.getAttribute(e);null!==o&&(r[e]=y(o))}if(u.valueFrom){const t=((t,n)=>{try{const e=t.querySelector(n.selector)||(t.parentElement?t.parentElement.querySelector(n.selector):null);if(!e)return null;const r=n.attr?e.getAttribute(n.attr):e.textContent||"";if(null===r)return null;const i=y(r.replace(/\s+/g," ").trim());return i.length>o?i.slice(0,o):i}catch(t){return null}})(n,u.valueFrom);null!==t&&(r[u.valueFrom.as]=t)}u.selectorPath&&(r.selector_path=((t,n=5)=>{try{const e=[];let r=t,o=0;for(;r&&1===r.nodeType&&o<n;){let t=r.tagName.toLowerCase();if(r.id){e.unshift(t+"#"+r.id);break}const n=Array.from(r.classList).slice(0,2).join(".");n&&(t+="."+n),e.unshift(t),r=r.parentElement,o++}return e.join(" > ")}catch(t){return""}})(n)),u.position&&(r.x=e.clientX,r.y=e.clientY)}catch(t){}return r.rule_id=t.id,t.name&&(r.rule_name=t.name),t.event&&t.event.name&&(r.event_name=t.event.name),r.tag=n.tagName.toLowerCase(),r}function k(t){try{t()}catch(t){}}function O(){try{return"undefined"!=typeof location?location.href:""}catch(t){return""}}function S(t,n){return"number"!=typeof t||isNaN(t)?n:t}function A(t){return t<0?0:t>1?1:t}const T="__cnvPatched";function I(){try{return"undefined"!=typeof location?location.href:""}catch(t){return""}}const P=["q","s","query","search","keyword"],_={spa:!0,outboundClicks:!0,scroll:!0,downloads:!0,siteSearch:!0},M={spa:!1,outboundClicks:!1,scroll:!1,downloads:!1,siteSearch:!1};function D(t){try{t()}catch(t){}}function U(t,n,e,r){return new(e||(e=Promise))((o,i)=>{function c(t){try{l(r.next(t))}catch(t){i(t)}}function u(t){try{l(r.throw(t))}catch(t){i(t)}}function l(t){var n;t.done?o(t.value):(n=t.value,n instanceof e?n:new e(t=>{t(n)})).then(c,u)}l((r=r.apply(t,n||[])).next())})}"function"==typeof SuppressedError&&SuppressedError;const C="undefined"!=typeof window&&"undefined"!=typeof document;function N(t){if(!C)return null;try{const n=document.cookie;if(!n)return null;const e=encodeURIComponent(t),r=n.split(";");for(let n=0;n<r.length;n++){const o=r[n].indexOf("=");if(o<0)continue;const i=r[n].slice(0,o).trim();if(i===e||i===t)try{return decodeURIComponent(r[n].slice(o+1))}catch(t){return r[n].slice(o+1)}}return null}catch(t){return null}}function $(t,n,e={}){var r,o,i;if(!C)return!1;try{let c=`${encodeURIComponent(t)}=${encodeURIComponent(n)}`;if(c+=`; path=${null!==(r=e.path)&&void 0!==r?r:"/"}`,e.domain&&(c+=`; domain=${e.domain}`),"number"==typeof e.maxAgeDays){const t=Math.floor(86400*e.maxAgeDays);c+=`; max-age=${t}`,c+=`; expires=${new Date(Date.now()+1e3*t).toUTCString()}`}return c+=`; SameSite=${null!==(o=e.sameSite)&&void 0!==o?o:"Lax"}`,(null!==(i=e.secure)&&void 0!==i?i:"undefined"!=typeof location&&"https:"===location.protocol)&&(c+="; Secure"),document.cookie=c,N(t)===n}catch(t){return!1}}function L(){if(!C)return!1;try{const t="__cnv_probe__";return localStorage.setItem(t,"1"),localStorage.removeItem(t),!0}catch(t){return!1}}function R(t){if(!L())return null;try{return localStorage.getItem(t)}catch(t){return null}}function q(t,n){if(!L())return!1;try{return localStorage.setItem(t,n),!0}catch(t){return!1}}function z(t){if(!L())return!1;try{return localStorage.removeItem(t),!0}catch(t){return!1}}function E(){if(!C)return!1;try{const t="__cnv_probe__";return sessionStorage.setItem(t,"1"),sessionStorage.removeItem(t),!0}catch(t){return!1}}const B={path:"/config",timeoutMs:4e3,ttlMs:3e5};function J(t,n){var e,r;const o=null!=n?n:Object.assign({enabled:!0},B);return void 0===t?Object.assign({},o):!0===t?Object.assign(Object.assign({},o),{enabled:!0}):!1===t?Object.assign(Object.assign({},o),{enabled:!1}):{enabled:null===(e=t.enabled)||void 0===e||e,path:null!==(r=t.path)&&void 0!==r?r:o.path,timeoutMs:"number"==typeof t.timeoutMs?t.timeoutMs:o.timeoutMs,ttlMs:"number"==typeof t.ttlMs?t.ttlMs:o.ttlMs}}function W(t){return"_cnv_cfg_"+t}function Z(t){const n=R(W(t));if(!n)return null;try{const t=JSON.parse(n);return t&&"object"==typeof t&&t.envelope?t:null}catch(t){return null}}function G(t,n,e){try{const r={etag:n,envelope:e,fetchedAt:Date.now()};q(W(t),JSON.stringify(r))}catch(t){}}function F(t){const n=null==t?void 0:t.buttonTracking;if(!n||!1===n.enabled)return null;const e=Array.isArray(n.rules)?n.rules:[];return 0===e.length?null:{rules:e,globalThrottle:n.globalThrottle}}const Q=["gclid","fbclid","ttclid","msclkid","dclid"],V=[["utm_source","source"],["utm_medium","medium"],["utm_campaign","name"],["utm_term","term"],["utm_content","content"],["utm_id","id"]];function H(t,n){try{return t()}catch(t){return n}}function K(){const t=H(()=>window.location.href,"");let n="",e="",r="";if(t)try{const o=new URL(t);n=o.pathname,e=o.search,r=o.hash}catch(t){}return{url:t,path:n,search:e,hash:r,title:H(()=>document.title,""),referrer:H(()=>document.referrer,"")}}function X(t){var n,e;let r="@cnv-vn/track",o="0.0.0-dev";try{r="@cnv-vn/track"}catch(t){}try{o="0.2.0-beta.4"}catch(t){}return{name:null!==(n=null==t?void 0:t.name)&&void 0!==n?n:r,version:null!==(e=null==t?void 0:t.version)&&void 0!==e?e:o}}const Y="0123456789abcdef";function tt(t){return Y[t>>>4&15]+Y[15&t]}function nt(){if("undefined"!=typeof crypto){if("function"==typeof crypto.randomUUID)return crypto.randomUUID();if("function"==typeof crypto.getRandomValues){const t=new Uint8Array(16);return crypto.getRandomValues(t),t[6]=15&t[6]|64,t[8]=63&t[8]|128,tt(t[0])+tt(t[1])+tt(t[2])+tt(t[3])+"-"+tt(t[4])+tt(t[5])+"-"+tt(t[6])+tt(t[7])+"-"+tt(t[8])+tt(t[9])+"-"+tt(t[10])+tt(t[11])+tt(t[12])+tt(t[13])+tt(t[14])+tt(t[15])}}return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{const n=16*Math.random()|0;return("x"===t?n:3&n|8).toString(16)})}const et=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;function rt(t){return"string"==typeof t&&et.test(t)}const ot="_cnv_cid";function it(t={}){const n=N(ot),e=R(ot);let r=null;return rt(n)?r=n:rt(e)&&(r=e),r||(r=nt()),ct(r,t),r}function ct(t,n={}){var e;$(ot,t,{domain:n.cookieDomain,maxAgeDays:null!==(e=n.cookieMaxAgeDays)&&void 0!==e?e:730,sameSite:"Lax"}),q(ot,t)}const ut="1.0";function lt(){return(new Date).toISOString()}function st(t,n){var e;const r=null!==(e=n.timestamp)&&void 0!==e?e:lt(),o=Object.assign(Object.assign({},n.context),{projectId:n.projectId,schemaVersion:ut}),i={type:t,messageId:nt(),anonymousId:n.anonymousId,timestamp:r,originalTimestamp:r,context:o};return n.userId&&(i.userId=n.userId),n.sessionId&&(i.sessionId=n.sessionId),n.integrations&&(i.integrations=n.integrations),i}const at="_cnv_sid";function ft(t){if(!t)return null;const n=t.lastIndexOf(".");if(n<0)return null;const e=t.slice(0,n),r=Number(t.slice(n+1));return!rt(e)||!Number.isFinite(r)||r<=0?null:{id:e,lastActivity:r}}function dt(t={}){const n=Date.now(),e=(t=>{var n;return 6e4*(null!==(n=t.timeoutMinutes)&&void 0!==n?n:30)})(t),r=ft(N(at)),o=ft((t=>{if(!E())return null;try{return sessionStorage.getItem(t)}catch(t){return null}})(at));let i=null;for(const t of[r,o])t&&(n-t.lastActivity>e||(!i||t.lastActivity>i.lastActivity)&&(i=t));const c=i?{id:i.id,lastActivity:n}:{id:nt(),lastActivity:n};return ht(c,t),c.id}function ht(t,n={}){var e;const r=(t=>`${t.id}.${t.lastActivity}`)(t),o=null!==(e=n.timeoutMinutes)&&void 0!==e?e:30;$(at,r,{domain:n.cookieDomain,maxAgeDays:o/1440,sameSite:"Lax"}),((t,n)=>{if(!E())return!1;try{return sessionStorage.setItem(t,n),!0}catch(t){return!1}})(at,r)}class yt{constructor(t){var n,e;Object.defineProperty(this,"config",{enumerable:!0,configurable:!0,writable:!0,value:t}),Object.defineProperty(this,"storageKey",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"maxMessages",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"flushing",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"onlineHandler",{enumerable:!0,configurable:!0,writable:!0,value:null}),this.storageKey=null!==(n=t.storageKey)&&void 0!==n?n:"_cnv_rq",this.maxMessages=null!==(e=t.maxMessages)&&void 0!==e?e:100,this.installOnlineListener()}stash(t){if(t&&0!==t.length)try{const n=this.read();for(n.push(t);n.length>1&&vt(n)>this.maxMessages;)n.shift();this.write(n),this.config.debug&&console.log("[cnv-track] retry queued",t.length,"buffered",vt(n))}catch(t){}}flush(){if(this.flushing||"undefined"!=typeof navigator&&!1===navigator.onLine)return Promise.resolve();const t=this.read();if(0===t.length)return Promise.resolve();this.flushing=!0,this.write([]);const n=()=>{this.flushing=!1};return t.reduce((t,n)=>t.then(()=>this.config.resend(n)),Promise.resolve()).then(n,n)}size(){return vt(this.read())}clear(){try{z(this.storageKey)}catch(t){}}destroy(){if(this.onlineHandler){try{window.removeEventListener("online",this.onlineHandler)}catch(t){}this.onlineHandler=null}}installOnlineListener(){if("undefined"==typeof window)return;const t=()=>{this.flush()};try{window.addEventListener("online",t),this.onlineHandler=t}catch(t){}}read(){const t=R(this.storageKey);if(!t)return[];try{const n=JSON.parse(t);return Array.isArray(n)?n.filter(t=>Array.isArray(t)&&t.length>0):[]}catch(t){return[]}}write(t){0!==t.length?q(this.storageKey,JSON.stringify(t)):z(this.storageKey)}}function vt(t){let n=0;for(const e of t)n+=e.length;return n}class pt{constructor(t){Object.defineProperty(this,"config",{enumerable:!0,configurable:!0,writable:!0,value:t}),Object.defineProperty(this,"buffer",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"timer",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"destroyed",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"handlers",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"retryQueue",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.retryQueue=new yt({debug:t.debug,resend:t=>this.send(t)}),this.installPageLifecycleHandlers(),this.retryQueue.flush()}setConfig(t){this.config=Object.assign(Object.assign({},this.config),t)}enqueue(t){this.destroyed||(this.buffer.push(t),this.buffer.length>=this.config.flushAt?this.flush():this.timer||(this.timer=setTimeout(()=>{this.timer=null,this.flush()},this.config.flushInterval)))}flush(){if(this.timer&&(clearTimeout(this.timer),this.timer=null),0===this.buffer.length)return Promise.resolve();const t=this.buffer;return this.buffer=[],this.send(t)}bufferedCount(){return this.buffer.length}destroy(){this.destroyed||(this.destroyed=!0,this.timer&&(clearTimeout(this.timer),this.timer=null),this.uninstallPageLifecycleHandlers(),this.retryQueue.destroy())}send(t){try{return this.config.useBatch?this.sendBatch(t):Promise.all(t.map(t=>this.sendSingle(t))).then(()=>{})}catch(t){return this.config.debug&&console.warn("[cnv-track] send failed synchronously; dropped batch",t),Promise.resolve()}}sendBatch(t){var n;const e=lt(),r={batch:t.map(t=>mt(t,e)),context:Object.assign(Object.assign({},null!==(n=this.config.batchContext)&&void 0!==n?n:{}),{projectId:this.config.projectId,sentAt:e}),sentAt:e};return this.post(this.batchUrl(),r,t)}sendSingle(t){const n=mt(t,lt());return this.post(this.singleUrl(t.type),n,[t])}batchUrl(){return this.config.endpoint+this.config.batchPath+"?projectId="+encodeURIComponent(this.config.projectId)}singleUrl(t){const n=this.config.singlePath.replace("{type}",t);return this.config.endpoint+n+"?projectId="+encodeURIComponent(this.config.projectId)}post(t,n,e){const r=JSON.stringify(n),o=((t,n)=>{try{return new Blob([t],{type:n})}catch(t){return null}})(r,this.config.contentType),i=o?o.size:(t=>{try{return new Blob([t]).size}catch(n){return t.length}})(r),c=i>65536?null:e;return c&&"undefined"!=typeof navigator&&!1===navigator.onLine?(this.retryQueue.stash(c),this.config.debug&&console.log("[cnv-track] offline; queued for retry",t),Promise.resolve()):o&&this.sendViaBeacon(t,o)?(this.config.debug&&console.log("[cnv-track] beacon",t),Promise.resolve()):this.sendViaFetch(t,r,c)}sendViaBeacon(t,n){if("undefined"==typeof navigator||"function"!=typeof navigator.sendBeacon)return!1;if(n.size>65536)return!1;try{return navigator.sendBeacon(t,n)}catch(t){return!1}}sendViaFetch(t,n,e){return"function"!=typeof fetch?(this.config.debug&&console.warn("[cnv-track] no transport available; queued for retry"),e&&this.retryQueue.stash(e),Promise.resolve()):fetch(t,{method:"POST",headers:{"Content-Type":this.config.contentType},body:n,keepalive:!0,credentials:"omit",mode:"cors"}).then(n=>{this.config.debug&&console.log("[cnv-track] fetch flushed",t,n.status)}).catch(n=>{this.config.debug&&console.warn("[cnv-track] flush failed; queued for retry",t,n),e&&this.retryQueue.stash(e)})}installPageLifecycleHandlers(){if("undefined"==typeof window||"undefined"==typeof document)return;const t=()=>{this.flush()},n=()=>{"hidden"===document.visibilityState&&this.flush()};try{window.addEventListener("pagehide",t),document.addEventListener("visibilitychange",n),this.handlers={pagehide:t,visibility:n}}catch(t){}}uninstallPageLifecycleHandlers(){if(this.handlers){try{window.removeEventListener("pagehide",this.handlers.pagehide),document.removeEventListener("visibilitychange",this.handlers.visibility)}catch(t){}this.handlers=null}}}function mt(t,n){return Object.assign(Object.assign({},t),{sentAt:n})}const bt="_cnv_uid",gt="_cnv_traits";function wt(){return N(bt)||R(bt)}const xt={endpoint:"https://tracking.cnvcdp.com/js/v1",batchPath:"/batch",singlePath:"/{type}",useBatch:!0,contentType:"text/plain",debug:!1,allowAdTracking:!0,cookieMaxAgeDays:730,sessionTimeoutMinutes:30,flushAt:20,flushInterval:5e3,autoPageview:!0,autotrack:!1,integrations:{},remoteConfig:J(void 0)},jt={analytics:!0,marketing:!0};function kt(t,n){if(!Array.isArray(n)||0===n.length)return;const e=n;try{switch(e[0]){case"init":t.init(e[1],e[2]);break;case"pageview":t.pageview(e[1],e[2]);break;case"page":t.page(e[1],e[2]);break;case"screen":t.screen(e[1],e[2]);break;case"track":t.track(e[1],e[2]);break;case"identify":t.identify(e[1],e[2]);break;case"alias":t.alias(e[1],e[2]);break;case"group":t.group(e[1],e[2]);break;case"reset":t.reset();break;case"flush":t.flush();break;case"consent":t.consent(e[1]);break;case"set":t.set(e[1])}}catch(t){}}const Ot=/^(https:|zalo:)/i;class St extends Error{constructor(t){super(`loginWithZalo() thất bại: ${t}`),Object.defineProperty(this,"reason",{enumerable:!0,configurable:!0,writable:!0,value:t}),this.name="ZaloQrLoginError"}}function At(t,n,e,r){return`${t}${n}?${new URLSearchParams(Object.assign({projectId:e},r)).toString()}`}function Tt(t,n){return U(this,void 0,void 0,function*(){var e,r,o;if(!t.projectId||!t.endpoint)throw new St("not-initialized");if(!t.zaloQrLoginEnabled)throw new St("disabled");if(!t.consentGranted)throw new St("consent-required");const i={preferSse:null===(e=null==n?void 0:n.preferSse)||void 0===e||e,pollIntervalMs:null!==(r=null==n?void 0:n.pollIntervalMs)&&void 0!==r?r:2e3,autoIdentify:null===(o=null==n?void 0:n.autoIdentify)||void 0===o||o},c=t.projectId,u=t.endpoint,l=yield function(t,n){return U(this,void 0,void 0,function*(){const e="undefined"!=typeof AbortController?new AbortController:null,r=e?setTimeout(()=>e.abort(),8e3):null;let o;try{o=yield fetch(At(t,"/zalo-qr/session",n),{method:"POST",credentials:"omit",mode:"cors",signal:e?e.signal:void 0})}catch(t){throw new St("network")}finally{r&&clearTimeout(r)}if(!o.ok)throw new St(401===(i=o.status)?"invalid-project-key":403===i?"project-suspended":"network");var i;return(t=>{const n=t;if(!n||"string"!=typeof n.sessionToken||!n.sessionToken||"string"!=typeof n.miniAppDeepLink||!Ot.test(n.miniAppDeepLink)||"number"!=typeof n.expiresInSeconds||!Number.isFinite(n.expiresInSeconds)||n.expiresInSeconds<=0)throw new St("network");return{sessionToken:n.sessionToken,miniAppDeepLink:n.miniAppDeepLink,expiresInSeconds:n.expiresInSeconds}})(yield o.json())})}(u,c),s=((t,n,e,r,o)=>{let i=!1,c=null,u=null,l=null,s=null,a=null;const f=()=>{c&&(c.close(),c=null),null!==u&&(clearInterval(u),u=null),null!==l&&(clearTimeout(l),l=null),null!==s&&(clearTimeout(s),s=null)};return{promise:new Promise((d,h)=>{a=h;const y=t=>{i||(i=!0,f(),t())},v=t=>{"success"===t.status?y(()=>d((t=>({contactId:t.contactId,fullName:t.fullName,level:t.level,xp:t.xp}))(t))):"denied"===t.status?y(()=>h(new St("denied"))):"expired"===t.status&&y(()=>h(new St("expired")))},p=()=>{null!==u||i||(u=setInterval(()=>{fetch(At(t,"/zalo-qr/status",n,{sessionToken:e}),{method:"GET",credentials:"omit",mode:"cors"}).then(t=>404===t.status?v({status:"expired"}):t.ok?t.json().then(t=>v(t)):void 0).catch(()=>{})},o.pollIntervalMs))};if(o.preferSse&&"undefined"!=typeof EventSource)try{c=new EventSource(At(t,"/zalo-qr/stream",n,{sessionToken:e})),c.addEventListener("success",t=>{try{v(JSON.parse(t.data))}catch(t){}}),c.addEventListener("denied",()=>v({status:"denied"})),c.onerror=()=>{null!==s||i||(s=setTimeout(()=>{s=null,i||(c&&(c.close(),c=null),p())},3e3))}}catch(t){p()}else p();l=setTimeout(()=>{y(()=>h(new St("expired")))},1e3*r)}),cancel(){i||(i=!0,f(),null==a||a(new St("cancelled")))}}})(u,c,l.sessionToken,l.expiresInSeconds,i),a=s.promise.then(n=>{try{if(i.autoIdentify&&null!=n.contactId){const e=String(n.contactId),r=t.getUserId();null!=r&&r!==e?t.alias(e,r):t.identify(e,Object.assign(Object.assign(Object.assign({},n.fullName?{name:n.fullName}:{}),n.level?{level:n.level}:{}),null!=n.xp?{xp:n.xp}:{}))}}catch(t){}return n});return{sessionToken:l.sessionToken,qrPayload:l.miniAppDeepLink,expiresInSeconds:l.expiresInSeconds,result:a,cancel:s.cancel,retry(){return s.cancel(),Tt(t,n)}}})}const It="0.2.0-beta.4",Pt="@cnv-vn/track",_t=function(){let o=null,i=Object.assign({},xt),c=Object.assign({},jt),u=null,l=!1,s=null,a=null;function f(t){const n=Object.assign({},i);return t?(void 0!==t.endpoint&&(n.endpoint=(e=t.endpoint).endsWith("/")?e.slice(0,-1):e),void 0!==t.batchPath&&(n.batchPath=t.batchPath),void 0!==t.singlePath&&(n.singlePath=t.singlePath),void 0!==t.useBatch&&(n.useBatch=t.useBatch),void 0!==t.contentType&&(n.contentType=t.contentType),void 0!==t.debug&&(n.debug=t.debug),void 0!==t.allowAdTracking&&(n.allowAdTracking=t.allowAdTracking),void 0!==t.cookieDomain&&(n.cookieDomain=t.cookieDomain),void 0!==t.cookieMaxAgeDays&&(n.cookieMaxAgeDays=t.cookieMaxAgeDays),void 0!==t.sessionTimeoutMinutes&&(n.sessionTimeoutMinutes=t.sessionTimeoutMinutes),void 0!==t.flushAt&&(n.flushAt=t.flushAt),void 0!==t.flushInterval&&(n.flushInterval=t.flushInterval),void 0!==t.autoPageview&&(n.autoPageview=t.autoPageview),void 0!==t.autotrack&&(n.autotrack=t.autotrack),void 0!==t.integrations&&(n.integrations=t.integrations),void 0!==t.remoteConfig&&(n.remoteConfig=J(t.remoteConfig,i.remoteConfig)),n):n;var e}function d(){return u||(u=new pt({endpoint:i.endpoint,batchPath:i.batchPath,singlePath:i.singlePath,useBatch:i.useBatch,contentType:i.contentType,flushAt:i.flushAt,flushInterval:i.flushInterval,projectId:null!=o?o:"",debug:i.debug}),u)}function h(){var t;if(!o)return null;const n=((t={})=>{var n;const e={page:K(),screen:{width:H(()=>window.screen.width,0),height:H(()=>window.screen.height,0),density:H(()=>window.devicePixelRatio||1,1)},locale:H(()=>navigator.language||"",""),timezone:H(()=>Intl.DateTimeFormat().resolvedOptions().timeZone||"",""),userAgent:H(()=>navigator.userAgent||"",""),library:X(t.library)},r=((t,n=!0)=>{const e=H(()=>window.location.search,"");if(!e)return;let r;try{r=new URLSearchParams(e)}catch(t){return}const o={};let i=!1;for(const[t,n]of V){const e=r.get(t);e&&e.length>0&&(o[n]=e,i=!0)}if(n){const t={};for(const n of Q){const e=r.get(n);e&&e.length>0&&(t[n]=e)}Object.keys(t).length>0&&(o.clickIds=t,i=!0)}return i?o:void 0})(0,null===(n=t.allowAdTracking)||void 0===n||n);return r&&(e.campaign=r),e})({allowAdTracking:i.allowAdTracking});return c.analytics&&c.marketing||(n.consent=Object.assign({},c)),{anonymousId:it({cookieDomain:i.cookieDomain,cookieMaxAgeDays:i.cookieMaxAgeDays}),sessionId:dt({cookieDomain:i.cookieDomain,timeoutMinutes:i.sessionTimeoutMinutes}),userId:null!==(t=wt())&&void 0!==t?t:void 0,context:n,projectId:o,integrations:Object.keys(i.integrations).length>0?i.integrations:void 0}}function y(t){i.debug&&console.warn(`[cnv-track] ${t}() called before init()`)}function v(t,n){try{const e=h();if(!e)return y("pageview");const r=((t,n,e)=>{const r=st("page",e);return t&&(r.name=t),r.properties=null!=n?n:{},r})(t,((t,n)=>{const e={};return t&&(t.url&&(e.url=t.url),t.path&&(e.path=t.path),t.title&&(e.title=t.title),t.referrer&&(e.referrer=t.referrer),t.search&&(e.search=t.search)),Object.assign(Object.assign({},e),null!=n?n:{})})(e.context.page,n),e);d().enqueue(r)}catch(t){}}function p(t,n){v(t,n)}function m(t,n){try{if("string"!=typeof t||0===t.length)return;const e=h();if(!e)return y("track");const r=((t,n,e)=>{const r=st("track",e);return r.event=t,r.properties=null!=n?n:{},r})(t,n,e);d().enqueue(r)}catch(t){}}return{get initialized(){return l},get projectId(){return o},get endpoint(){return i.endpoint},isZaloQrLoginEnabled:()=>!!o&&(t=>{const n=Z(t);return!n||!1!==(null===(r=null==(e=n.envelope)?void 0:e.zaloQrLogin)||void 0===r?void 0:r.enabled);var e,r})(o),get consentGranted(){return c.analytics&&c.marketing},init(h,y){try{if(!h||"string"!=typeof h)return;if(i=f(y),(null==y?void 0:y.consent)&&(c=Object.assign(Object.assign({},c),y.consent)),o=h,u&&u.destroy(),u=null,d(),l=!0,it({cookieDomain:i.cookieDomain,cookieMaxAgeDays:i.cookieMaxAgeDays}),dt({cookieDomain:i.cookieDomain,timeoutMinutes:i.sessionTimeoutMinutes}),i.autoPageview&&v(),s){try{s()}catch(t){}s=null}const b={page(t,n){return p(t,n)},track(t,n){return m(t,n)}};if(i.autotrack){let o=i.autotrack;i.remoteConfig.enabled&&"object"==typeof o&&o.buttonTracking&&(o=Object.assign(Object.assign({},o),{buttonTracking:void 0})),s=function(o,i){const c=void 0===(u=i)||!1===u?Object.assign(Object.assign({},M),{searchParams:P}):!0===u?Object.assign(Object.assign({},_),{searchParams:P}):{spa:null===(l=u.spa)||void 0===l||l,outboundClicks:null===(s=u.outboundClicks)||void 0===s||s,scroll:null===(a=u.scroll)||void 0===a||a,downloads:null===(f=u.downloads)||void 0===f||f,siteSearch:null===(d=u.siteSearch)||void 0===d||d,downloadExtensions:u.downloadExtensions,searchParams:null!==(h=u.searchParams)&&void 0!==h?h:P,buttonTracking:u.buttonTracking};var u,l,s,a,f,d,h;const y=[];let v=null;function p(t){if(c.siteSearch)try{const n=null!=t?t:(()=>{try{return"undefined"!=typeof location?location.href:""}catch(t){return""}})();if(n===v)return;v=n;const e=((t,n=P)=>{try{if(!t){if("undefined"==typeof location)return null;t=location.href}const e=t instanceof URL?t:new URL(t,(()=>{try{return"undefined"!=typeof location?location.href:"http://localhost/"}catch(t){return"http://localhost/"}})());if(!e.search)return null;for(const t of n){const n=e.searchParams.get(t);if(null===n)continue;const r=n.trim();if(0!==r.length)return{query:r,param:t}}return null}catch(t){return null}})(n,c.searchParams);e&&D(()=>o.track("Site Searched",{query:e.query,param:e.param}))}catch(t){}}if(c.outboundClicks||c.downloads){const i=(o=>{var i;if("undefined"==typeof document)return()=>{};const c=new Set((null!==(i=o.downloadExtensions)&&void 0!==i?i:t).map(t=>t.toLowerCase())),u=!!o.onOutbound,l=!!o.onDownload;if(!u&&!l)return()=>{};function s(t){var i,s;try{if(0!==t.button)return;if(t.defaultPrevented)return;const a=(t=>{const e="function"==typeof t.composedPath?t.composedPath():[];if(e.length>0)for(const t of e)if(n(t))return t;let r=t.target;for(;r;){if(n(r))return r;r=r.parentNode}return null})(t);if(!a)return;const f=a.getAttribute("href");if(!f)return;if(/^(javascript:|mailto:|tel:|sms:)/i.test(f))return;if(f.startsWith("#"))return;const d=(t=>{try{return new URL(t,location.href)}catch(t){return null}})(f);if(!d)return;let h=!1;if(l){const t=a.hasAttribute("download"),n=(t=>{const n=e(t),r=n.lastIndexOf(".");return r<=0||r===n.length-1?null:n.slice(r+1).toLowerCase()})(d.pathname);(t||n&&c.has(n))&&(h=!0,null===(i=o.onDownload)||void 0===i||i.call(o,{url:d.href,fileName:e(d.pathname),fileExtension:null!=n?n:"",text:r(a)}))}u&&!h&&d.host!==(()=>{try{return"undefined"!=typeof location?location.hostname:""}catch(t){return""}})()&&d.host&&(null===(s=o.onOutbound)||void 0===s||s.call(o,{url:d.href,host:d.host,text:r(a),target:a.target||"_self"}))}catch(t){}}try{document.addEventListener("click",s,!0)}catch(t){return()=>{}}return()=>{try{document.removeEventListener("click",s,!0)}catch(t){}}})({downloadExtensions:c.downloadExtensions,onOutbound:c.outboundClicks?t=>D(()=>o.track("Clicked",t)):void 0,onDownload:c.downloads?t=>D(()=>o.track("File Downloaded",t)):void 0});y.push(i)}c.buttonTracking&&c.buttonTracking.rules&&c.buttonTracking.rules.length>0&&y.push(g(o,c.buttonTracking));let m=null;if(c.scroll&&(m=(t=>{if("undefined"==typeof window||"undefined"==typeof document)return{destroy(){},reset(){}};let n=!1,e=null,r=!1;function o(){if(e=null,!r&&!n)try{const e=document.documentElement,r=document.body,o=Math.max(e?e.scrollHeight:0,r?r.scrollHeight:0),i=Math.max(e?e.clientHeight:0,window.innerHeight||0);if(o<=i)return n=!0,c(),void t(90);((window.scrollY||(e?e.scrollTop:0)||0)+i)/o>=.9&&(n=!0,c(),t(90))}catch(t){}}function i(){if(null===e)try{e=window.requestAnimationFrame(o)}catch(t){o()}}function c(){try{window.removeEventListener("scroll",i),null!==e&&window.cancelAnimationFrame(e),e=null}catch(t){}}try{window.addEventListener("scroll",i,{passive:!0})}catch(t){try{window.addEventListener("scroll",i)}catch(t){}}try{window.requestAnimationFrame(o)}catch(t){o()}return{destroy(){r=!0,c()},reset(){if(!r){n=!1;try{window.addEventListener("scroll",i,{passive:!0})}catch(t){try{window.addEventListener("scroll",i)}catch(t){}}try{window.requestAnimationFrame(o)}catch(t){o()}}}}})(t=>{D(()=>o.track("Scrolled",{percent:t}))}),y.push(()=>null==m?void 0:m.destroy())),c.spa){const t=[],n=function(){if("undefined"==typeof window||"undefined"==typeof history)return()=>{};let n=I();function e(){try{const e=I();if(e===n)return;n=e,(n=>{const e=setTimeout(()=>{const n=t.indexOf(e);-1!==n&&t.splice(n,1),D(()=>o.page())},0);t.push(e),null==m||m.reset(),p(n)})(e)}catch(t){}}const r=history.pushState,i=history.replaceState,c=!0===r[T],u=!0===i[T];if(!c){function a(...t){r.apply(this,t),e()}a[T]=!0,history.pushState=a}if(!u){function f(...t){i.apply(this,t),e()}f[T]=!0,history.replaceState=f}const l=()=>e(),s=()=>e();try{window.addEventListener("popstate",l),window.addEventListener("hashchange",s)}catch(d){}return()=>{try{window.removeEventListener("popstate",l),window.removeEventListener("hashchange",s)}catch(t){}try{!c&&history.pushState[T]&&(history.pushState=r),!u&&history.replaceState[T]&&(history.replaceState=i)}catch(t){}}}();y.push(()=>{for(let n=0;n<t.length;n++)clearTimeout(t[n]);t.length=0,n()})}return p(),()=>{for(;y.length>0;){const t=y.pop();try{null==t||t()}catch(t){}}v=null}}(b,o)}if(a){try{a()}catch(t){}a=null}if(i.remoteConfig.enabled&&o){const t=t=>{if(a){try{a()}catch(t){}a=null}t&&t.rules&&t.rules.length>0&&(a=g(b,t))},n=(t=>{const n=Z(t);return n?F(n.envelope):null})(o);n&&t(n),function(t){return U(this,void 0,void 0,function*(){if(!t.projectId)return{status:"error"};const n=Z(t.projectId);if(n&&Date.now()-n.fetchedAt<t.ttlMs)return{status:"unchanged"};const e=yield function(t){return U(this,void 0,void 0,function*(){var n;if("function"!=typeof fetch)return null;const e=t.endpoint+t.path+"?projectId="+encodeURIComponent(t.projectId),r="undefined"!=typeof AbortController?new AbortController:null,o=r?setTimeout(()=>r.abort(),t.timeoutMs):null;try{const o={};t.etag&&(o["If-None-Match"]=t.etag);const i=yield fetch(e,{method:"GET",headers:o,credentials:"omit",mode:"cors",signal:r?r.signal:void 0});if(304===i.status)return{envelope:null,etag:null!==(n=t.etag)&&void 0!==n?n:"",notModified:!0};if(!i.ok)return null;const c=i.headers&&"function"==typeof i.headers.get?i.headers.get("ETag"):null;return{envelope:yield i.json(),etag:null!=c?c:"",notModified:!1}}catch(t){return null}finally{o&&clearTimeout(o)}})}({endpoint:t.endpoint,path:t.path,projectId:t.projectId,timeoutMs:t.timeoutMs,etag:null==n?void 0:n.etag});return e?e.notModified?(n&&G(t.projectId,n.etag,n.envelope),{status:"unchanged"}):e.envelope?(G(t.projectId,e.etag,e.envelope),{status:"updated",buttonTracking:F(e.envelope)}):{status:"error"}:{status:"error"}})}({endpoint:i.endpoint,path:i.remoteConfig.path,projectId:o,timeoutMs:i.remoteConfig.timeoutMs,ttlMs:i.remoteConfig.ttlMs}).then(n=>{"updated"===n.status&&t(n.buttonTracking)}).catch(()=>{})}}catch(t){}},pageview:v,page:p,screen(t,n){try{const e=h();if(!e)return y("screen");const r=((t,n,e)=>{const r=st("screen",e);return t&&(r.name=t),r.properties=null!=n?n:{},r})(t,n,e);d().enqueue(r)}catch(t){}},track:m,identify(t,n){try{if("string"!=typeof t||0===t.length)return;((t,n,e={})=>{var r,o;if(t&&($(bt,t,{domain:e.cookieDomain,maxAgeDays:null!==(r=e.cookieMaxAgeDays)&&void 0!==r?r:730,sameSite:"Lax"}),q(bt,t),null!=n)){const t=null!==(o=(()=>{const t=R(gt);if(!t)return null;try{const n=JSON.parse(t);return n&&"object"==typeof n&&!Array.isArray(n)?n:null}catch(t){return null}})())&&void 0!==o?o:{},e=Object.assign(Object.assign({},t),n);try{q(gt,JSON.stringify(e))}catch(t){}}})(t,n,{cookieDomain:i.cookieDomain,cookieMaxAgeDays:i.cookieMaxAgeDays});const e=h();if(!e)return y("identify");const r=((t,n,e)=>{var r;const o=st("identify",e);return t&&(o.userId=t),o.traits=null!==(r=n)&&void 0!==r?r:{},o})(t,n,e);d().enqueue(r)}catch(t){}},alias(t,n){try{if("string"!=typeof t||0===t.length)return;const e=h();if(!e)return y("alias");const r=((t,n,e)=>{const r=st("alias",e);return t&&(r.userId=t),r.previousId=null!=n?n:e.anonymousId,r})(t,n,e);d().enqueue(r)}catch(t){}},group(t,n){try{if("string"!=typeof t||0===t.length)return;const e=h();if(!e)return y("group");const r=((t,n,e)=>{const r=st("group",e);return r.groupId=t,r.traits=null!=n?n:{},r})(t,n,e);d().enqueue(r)}catch(t){}},reset(){try{((t={})=>{((t,n={})=>{var e;if(!C)return!1;try{let r=`${encodeURIComponent(t)}=`;return r+=`; path=${null!==(e=n.path)&&void 0!==e?e:"/"}`,n.domain&&(r+=`; domain=${n.domain}`),r+="; max-age=0",r+="; expires=Thu, 01 Jan 1970 00:00:00 GMT",document.cookie=r,null===N(t)}catch(t){return!1}})(bt,{domain:t.cookieDomain}),z(bt),z(gt)})({cookieDomain:i.cookieDomain}),((t={})=>{ct(nt(),t)})({cookieDomain:i.cookieDomain,cookieMaxAgeDays:i.cookieMaxAgeDays}),((t={})=>{ht({id:nt(),lastActivity:Date.now()},t)})({cookieDomain:i.cookieDomain,timeoutMinutes:i.sessionTimeoutMinutes})}catch(t){}},flush(){try{u&&u.flush()}catch(t){}},consent(t){try{c=Object.assign(Object.assign({},c),t)}catch(t){}},set(t){try{i=f(t),t.consent&&(c=Object.assign(Object.assign({},c),t.consent)),u&&u.setConfig({endpoint:i.endpoint,batchPath:i.batchPath,singlePath:i.singlePath,useBatch:i.useBatch,contentType:i.contentType,flushAt:i.flushAt,flushInterval:i.flushInterval,debug:i.debug})}catch(t){}},destroy(){if(s){try{s()}catch(t){}s=null}if(a){try{a()}catch(t){}a=null}u&&u.destroy(),u=null,l=!1,o=null,i=Object.assign({},xt),c=Object.assign({},jt)}}}();function Mt(t){return Tt({projectId:_t.projectId,endpoint:_t.endpoint,zaloQrLoginEnabled:_t.isZaloQrLoginEnabled(),consentGranted:_t.consentGranted,identify:_t.identify,alias:_t.alias,getUserId:wt},t)}"undefined"!=typeof window&&(t=>{if("undefined"==typeof window)return()=>{};const n=window.cnvQ;if(n&&n.__loaded)return()=>{};const e=window.cnvQ=null!=n?n:[],r=e.splice(0,e.length);e.push.bind(e),e.push=(...n)=>{for(const e of n)kt(t,e);return e.length},e.__loaded=!0;for(const n of r)kt(t,n)})(_t);const Dt=Object.assign(_t,{version:It,name:Pt,schemaVersion:ut,loginWithZalo:Mt});export{Pt as NAME,ut as SCHEMA_VERSION,It as VERSION,St as ZaloQrLoginError,Dt as default,Mt as loginWithZalo};
@@ -1,6 +0,0 @@
1
- /*!
2
- * @cnv-vn/track v0.2.0-beta.4
3
- * (c) 2026 CNV
4
- * Released under the UNLICENSED license.
5
- */
6
- !function(t){const n=["pdf","doc","docx","xls","xlsx","ppt","pptx","txt","csv","rtf","zip","rar","7z","tar","gz","mp3","mp4","mov","wav","avi","mkv","dmg","exe","pkg","apk","msi","svg"];function e(t){return!!t&&"object"==typeof t&&1===t.nodeType&&"A"===t.tagName}function r(t){const n=t.lastIndexOf("/");return-1===n?t:t.slice(n+1)}function o(t){var n,e,r;let o=(null!==(n=t.textContent)&&void 0!==n?n:"").trim();return o||(o=(null!==(e=t.getAttribute("aria-label"))&&void 0!==e?e:"").trim()),o||(o=(null!==(r=t.getAttribute("title"))&&void 0!==r?r:"").trim()),o.length>200?o.slice(0,200):o}const i=200;function c(t){let n="";try{n=(t.textContent||"").replace(/\s+/g," ").trim(),n||(n=(t.getAttribute("aria-label")||"").trim()),n||(n=(t.getAttribute("title")||"").trim()),n=n.normalize("NFC")}catch(t){return""}return n.length>i?n.slice(0,i):n}function u(t){const n=!1!==t.caseInsensitive;if("regex"===t.mode)return{mode:"regex",needle:t.value,ci:n,re:b(t.value,n)};const e=t.value.normalize("NFC");return{mode:t.mode,needle:n?e.toLowerCase():e,ci:n,re:null}}function l(t,n){try{return t.matches(n)}catch(t){return!1}}function s(t){try{if("A"===t.tagName){const n=t.getAttribute("href");return n?m(n):null}const n=t.getAttribute("formaction");if(n)return m(n);const e=t.getAttribute("data-href");if(e)return m(e);const r=t.closest("form");if(r){const t=r.getAttribute("action");if(t)return m(t)}return null}catch(t){return null}}function a(t){return"regex"===t.mode?{mode:"regex",needle:t.value,re:b(t.value,!0)}:{mode:t.mode,needle:t.value.toLowerCase(),re:null}}function f(t){if("startsWith"===t.mode)return{mode:"startsWith",needle:t.value,re:null};const n="glob"===t.mode?"^"+t.value.replace(/[.+^${}()|[\]\\?]/g,"\\$&").replace(/\*/g,".*")+"$":t.value;return{mode:t.mode,needle:t.value,re:b(n,!1)}}function d(t,n){return"startsWith"===t.mode?0===n.indexOf(t.needle):!t.re||g(t.re,n)}const h=/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,y=/\+?\d[\d\s().-]{7,}\d/g;function v(t){if(!t)return t;try{return t.replace(h,"[email]").replace(y,"[phone]")}catch(n){return t}}function p(t){return!!t&&"object"==typeof t&&1===t.nodeType}function m(t){try{return new URL(t,location.href).href}catch(n){return t}}function b(t,n){try{return!t||t.length>1e3?null:new RegExp(t,n?"i":"")}catch(t){return null}}function g(t,n){try{return t.test(n)}catch(t){return!1}}function w(t,n){if("undefined"==typeof document)return()=>{};const e=(t=>{const n=t.globalThrottle||{},e=[],r=t.rules||[];for(let t=0;t<r.length;t++){const o=r[t];if(!o||!1===o.enabled)continue;if(!o.match||!o.event)continue;const i=o.match,c=o.throttle||{};e.push({rule:o,elementSpec:x(o),selector:i.selector||null,text:i.text?u(i.text):null,dest:i.destinationUrl?a(i.destinationUrl):null,urlScope:o.urlScope?f(o.urlScope):null,dedupeWindowMs:A(c.dedupeWindowMs,A(n.dedupeWindowMs,500)),maxPerPageview:A(c.maxPerPageview,A(n.maxPerPageview,1/0)),samplingRate:T(A(c.samplingRate,A(n.samplingRate,1)))})}return e.sort((t,n)=>(t.rule.priority||0)-(n.rule.priority||0)),e})(n);if(0===e.length)return()=>{};const r=new WeakMap;let o=0;const i=t=>{let n=r.get(t);return void 0===n&&(n=++o,r.set(t,n)),String(n)},c=new Map,l=new Map;let s=S();function h(n){try{if(0!==n.button)return;const r=S();r!==s&&(s=r,l.clear(),c.clear());const o=(t=>{const n=[];try{const e="function"==typeof t.composedPath?t.composedPath():[];if(e&&e.length>0){for(const t of e)p(t)&&n.push(t);return n}let r=t.target;for(;r;)p(r)&&n.push(r),r=r.parentNode}catch(t){}return n})(n);if(0===o.length)return;const u=(()=>{try{return"undefined"!=typeof location?location.pathname+location.search:""}catch(t){return""}})();for(let r=0;r<e.length;r++){const s=e[r];if(s.urlScope&&!d(s.urlScope,u))continue;let a=null;for(let t=0;t<o.length;t++)if(j(s,o[t])){a=o[t];break}if(!a)continue;const f=s.rule.id;if((l.get(f)||0)>=s.maxPerPageview)return;const h=f+"#"+i(a),y=Date.now(),v=c.get(h);if(void 0!==v&&y-v<s.dedupeWindowMs)return;if(s.samplingRate<1&&Math.random()>=s.samplingRate)return;c.set(h,y),l.set(f,(l.get(f)||0)+1);const p=k(s.rule,a,n);return void O(()=>t.track("Clicked",p))}}catch(t){}}try{document.addEventListener("click",h,!0)}catch(t){return()=>{}}return()=>{try{document.removeEventListener("click",h,!0)}catch(t){}c.clear(),l.clear()}}function x(t){const n=t.match;return n.element?n.element:n.selector||n.id||n.dataAttr||n.classes&&n.classes.length>0||n.destinationUrl?"any":void 0}function j(t,n){if(!((t,n)=>{if(!n)return(t=>{const n=t.tagName;if("BUTTON"===n||"A"===n)return!0;if("INPUT"===n){const n=(t.getAttribute("type")||"").toLowerCase();return"submit"===n||"button"===n||"reset"===n}return"button"===t.getAttribute("role")})(t);if("any"===n)return!0;if("button"===n){const n=t.tagName;if("BUTTON"===n)return!0;if("INPUT"===n){const n=(t.getAttribute("type")||"").toLowerCase();return"submit"===n||"button"===n||"reset"===n}return"button"===t.getAttribute("role")}return"link"===n?"A"===t.tagName:l(t,n)})(n,t.elementSpec))return!1;const e=t.rule.match;return!(t.selector&&!l(n,t.selector)||void 0!==e.id&&!((t,n)=>t.id===n)(n,e.id)||e.classes&&e.classes.length>0&&!((t,n)=>{try{for(let e=0;e<n.length;e++)if(!t.classList.contains(n[e]))return!1;return!0}catch(t){return!1}})(n,e.classes)||e.dataAttr&&!((t,n,e)=>{try{return!!t.hasAttribute(n)&&(void 0===e||t.getAttribute(n)===e)}catch(t){return!1}})(n,e.dataAttr.name,e.dataAttr.value)||t.text&&!((t,n)=>{const e=c(t);if("regex"===n.mode)return!!n.re&&g(n.re,e);const r=n.ci?e.toLowerCase():e;return"exact"===n.mode?r===n.needle:"startsWith"===n.mode?0===r.indexOf(n.needle):-1!==r.indexOf(n.needle)})(n,t.text)||t.dest&&!((t,n)=>{const e=s(t);if(!e)return!1;if("regex"===n.mode)return!!n.re&&g(n.re,e);if("domain"===n.mode)try{return new URL(e).host.toLowerCase()===n.needle}catch(t){return!1}const r=e.toLowerCase();return"exact"===n.mode?r===n.needle:"startsWith"===n.mode?0===r.indexOf(n.needle):-1!==r.indexOf(n.needle)})(n,t.dest))}function k(t,n,e){const r={},o=t.event.staticProps;if(o)for(const t of Object.keys(o))r[t]=o[t];const u=t.capture;if(u)try{if(u.text){const t=v(c(n));t&&(r.text=t)}if(u.href){const t=s(n);t&&(r.href=t)}if(u.elementId&&n.id&&(r.element_id=n.id),u.classes&&(r.element_classes=Array.from(n.classList)),u.dataAttrs&&u.dataAttrs.length>0)for(let t=0;t<u.dataAttrs.length;t++){const e=u.dataAttrs[t],o=n.getAttribute(e);null!==o&&(r[e]=v(o))}if(u.valueFrom){const t=((t,n)=>{try{const e=t.querySelector(n.selector)||(t.parentElement?t.parentElement.querySelector(n.selector):null);if(!e)return null;const r=n.attr?e.getAttribute(n.attr):e.textContent||"";if(null===r)return null;const o=v(r.replace(/\s+/g," ").trim());return o.length>i?o.slice(0,i):o}catch(t){return null}})(n,u.valueFrom);null!==t&&(r[u.valueFrom.as]=t)}u.selectorPath&&(r.selector_path=((t,n=5)=>{try{const e=[];let r=t,o=0;for(;r&&1===r.nodeType&&o<n;){let t=r.tagName.toLowerCase();if(r.id){e.unshift(t+"#"+r.id);break}const n=Array.from(r.classList).slice(0,2).join(".");n&&(t+="."+n),e.unshift(t),r=r.parentElement,o++}return e.join(" > ")}catch(t){return""}})(n)),u.position&&(r.x=e.clientX,r.y=e.clientY)}catch(t){}return r.rule_id=t.id,t.name&&(r.rule_name=t.name),t.event&&t.event.name&&(r.event_name=t.event.name),r.tag=n.tagName.toLowerCase(),r}function O(t){try{t()}catch(t){}}function S(){try{return"undefined"!=typeof location?location.href:""}catch(t){return""}}function A(t,n){return"number"!=typeof t||isNaN(t)?n:t}function T(t){return t<0?0:t>1?1:t}const I="__cnvPatched";function _(){try{return"undefined"!=typeof location?location.href:""}catch(t){return""}}const P=["q","s","query","search","keyword"],M={spa:!0,outboundClicks:!0,scroll:!0,downloads:!0,siteSearch:!0},D={spa:!1,outboundClicks:!1,scroll:!1,downloads:!1,siteSearch:!1};function U(t){try{t()}catch(t){}}function C(t,n,e,r){return new(e||(e=Promise))((o,i)=>{function c(t){try{l(r.next(t))}catch(t){i(t)}}function u(t){try{l(r.throw(t))}catch(t){i(t)}}function l(t){var n;t.done?o(t.value):(n=t.value,n instanceof e?n:new e(t=>{t(n)})).then(c,u)}l((r=r.apply(t,n||[])).next())})}"function"==typeof SuppressedError&&SuppressedError;const N="undefined"!=typeof window&&"undefined"!=typeof document;function $(t){if(!N)return null;try{const n=document.cookie;if(!n)return null;const e=encodeURIComponent(t),r=n.split(";");for(let n=0;n<r.length;n++){const o=r[n].indexOf("=");if(o<0)continue;const i=r[n].slice(0,o).trim();if(i===e||i===t)try{return decodeURIComponent(r[n].slice(o+1))}catch(t){return r[n].slice(o+1)}}return null}catch(t){return null}}function L(t,n,e={}){var r,o,i;if(!N)return!1;try{let c=`${encodeURIComponent(t)}=${encodeURIComponent(n)}`;if(c+=`; path=${null!==(r=e.path)&&void 0!==r?r:"/"}`,e.domain&&(c+=`; domain=${e.domain}`),"number"==typeof e.maxAgeDays){const t=Math.floor(86400*e.maxAgeDays);c+=`; max-age=${t}`,c+=`; expires=${new Date(Date.now()+1e3*t).toUTCString()}`}return c+=`; SameSite=${null!==(o=e.sameSite)&&void 0!==o?o:"Lax"}`,(null!==(i=e.secure)&&void 0!==i?i:"undefined"!=typeof location&&"https:"===location.protocol)&&(c+="; Secure"),document.cookie=c,$(t)===n}catch(t){return!1}}function R(){if(!N)return!1;try{const t="__cnv_probe__";return localStorage.setItem(t,"1"),localStorage.removeItem(t),!0}catch(t){return!1}}function q(t){if(!R())return null;try{return localStorage.getItem(t)}catch(t){return null}}function z(t,n){if(!R())return!1;try{return localStorage.setItem(t,n),!0}catch(t){return!1}}function E(t){if(!R())return!1;try{return localStorage.removeItem(t),!0}catch(t){return!1}}function B(){if(!N)return!1;try{const t="__cnv_probe__";return sessionStorage.setItem(t,"1"),sessionStorage.removeItem(t),!0}catch(t){return!1}}const J={path:"/config",timeoutMs:4e3,ttlMs:3e5};function W(t,n){var e,r;const o=null!=n?n:Object.assign({enabled:!0},J);return void 0===t?Object.assign({},o):!0===t?Object.assign(Object.assign({},o),{enabled:!0}):!1===t?Object.assign(Object.assign({},o),{enabled:!1}):{enabled:null===(e=t.enabled)||void 0===e||e,path:null!==(r=t.path)&&void 0!==r?r:o.path,timeoutMs:"number"==typeof t.timeoutMs?t.timeoutMs:o.timeoutMs,ttlMs:"number"==typeof t.ttlMs?t.ttlMs:o.ttlMs}}function Z(t){return"_cnv_cfg_"+t}function G(t){const n=q(Z(t));if(!n)return null;try{const t=JSON.parse(n);return t&&"object"==typeof t&&t.envelope?t:null}catch(t){return null}}function F(t,n,e){try{const r={etag:n,envelope:e,fetchedAt:Date.now()};z(Z(t),JSON.stringify(r))}catch(t){}}function Q(t){const n=null==t?void 0:t.buttonTracking;if(!n||!1===n.enabled)return null;const e=Array.isArray(n.rules)?n.rules:[];return 0===e.length?null:{rules:e,globalThrottle:n.globalThrottle}}const V=["gclid","fbclid","ttclid","msclkid","dclid"],H=[["utm_source","source"],["utm_medium","medium"],["utm_campaign","name"],["utm_term","term"],["utm_content","content"],["utm_id","id"]];function K(t,n){try{return t()}catch(t){return n}}function X(){const t=K(()=>window.location.href,"");let n="",e="",r="";if(t)try{const o=new URL(t);n=o.pathname,e=o.search,r=o.hash}catch(t){}return{url:t,path:n,search:e,hash:r,title:K(()=>document.title,""),referrer:K(()=>document.referrer,"")}}function Y(t){var n,e;let r="@cnv-vn/track",o="0.0.0-dev";try{r="@cnv-vn/track"}catch(t){}try{o="0.2.0-beta.4"}catch(t){}return{name:null!==(n=null==t?void 0:t.name)&&void 0!==n?n:r,version:null!==(e=null==t?void 0:t.version)&&void 0!==e?e:o}}const tt="0123456789abcdef";function nt(t){return tt[t>>>4&15]+tt[15&t]}function et(){if("undefined"!=typeof crypto){if("function"==typeof crypto.randomUUID)return crypto.randomUUID();if("function"==typeof crypto.getRandomValues){const t=new Uint8Array(16);return crypto.getRandomValues(t),t[6]=15&t[6]|64,t[8]=63&t[8]|128,nt(t[0])+nt(t[1])+nt(t[2])+nt(t[3])+"-"+nt(t[4])+nt(t[5])+"-"+nt(t[6])+nt(t[7])+"-"+nt(t[8])+nt(t[9])+"-"+nt(t[10])+nt(t[11])+nt(t[12])+nt(t[13])+nt(t[14])+nt(t[15])}}return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{const n=16*Math.random()|0;return("x"===t?n:3&n|8).toString(16)})}const rt=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;function ot(t){return"string"==typeof t&&rt.test(t)}const it="_cnv_cid";function ct(t={}){const n=$(it),e=q(it);let r=null;return ot(n)?r=n:ot(e)&&(r=e),r||(r=et()),ut(r,t),r}function ut(t,n={}){var e;L(it,t,{domain:n.cookieDomain,maxAgeDays:null!==(e=n.cookieMaxAgeDays)&&void 0!==e?e:730,sameSite:"Lax"}),z(it,t)}const lt="1.0";function st(){return(new Date).toISOString()}function at(t,n){var e;const r=null!==(e=n.timestamp)&&void 0!==e?e:st(),o=Object.assign(Object.assign({},n.context),{projectId:n.projectId,schemaVersion:lt}),i={type:t,messageId:et(),anonymousId:n.anonymousId,timestamp:r,originalTimestamp:r,context:o};return n.userId&&(i.userId=n.userId),n.sessionId&&(i.sessionId=n.sessionId),n.integrations&&(i.integrations=n.integrations),i}const ft="_cnv_sid";function dt(t){if(!t)return null;const n=t.lastIndexOf(".");if(n<0)return null;const e=t.slice(0,n),r=Number(t.slice(n+1));return!ot(e)||!Number.isFinite(r)||r<=0?null:{id:e,lastActivity:r}}function ht(t={}){const n=Date.now(),e=(t=>{var n;return 6e4*(null!==(n=t.timeoutMinutes)&&void 0!==n?n:30)})(t),r=dt($(ft)),o=dt((t=>{if(!B())return null;try{return sessionStorage.getItem(t)}catch(t){return null}})(ft));let i=null;for(const t of[r,o])t&&(n-t.lastActivity>e||(!i||t.lastActivity>i.lastActivity)&&(i=t));const c=i?{id:i.id,lastActivity:n}:{id:et(),lastActivity:n};return yt(c,t),c.id}function yt(t,n={}){var e;const r=(t=>`${t.id}.${t.lastActivity}`)(t),o=null!==(e=n.timeoutMinutes)&&void 0!==e?e:30;L(ft,r,{domain:n.cookieDomain,maxAgeDays:o/1440,sameSite:"Lax"}),((t,n)=>{if(!B())return!1;try{return sessionStorage.setItem(t,n),!0}catch(t){return!1}})(ft,r)}class vt{constructor(t){var n,e;Object.defineProperty(this,"config",{enumerable:!0,configurable:!0,writable:!0,value:t}),Object.defineProperty(this,"storageKey",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"maxMessages",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"flushing",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"onlineHandler",{enumerable:!0,configurable:!0,writable:!0,value:null}),this.storageKey=null!==(n=t.storageKey)&&void 0!==n?n:"_cnv_rq",this.maxMessages=null!==(e=t.maxMessages)&&void 0!==e?e:100,this.installOnlineListener()}stash(t){if(t&&0!==t.length)try{const n=this.read();for(n.push(t);n.length>1&&pt(n)>this.maxMessages;)n.shift();this.write(n),this.config.debug&&console.log("[cnv-track] retry queued",t.length,"buffered",pt(n))}catch(t){}}flush(){if(this.flushing||"undefined"!=typeof navigator&&!1===navigator.onLine)return Promise.resolve();const t=this.read();if(0===t.length)return Promise.resolve();this.flushing=!0,this.write([]);const n=()=>{this.flushing=!1};return t.reduce((t,n)=>t.then(()=>this.config.resend(n)),Promise.resolve()).then(n,n)}size(){return pt(this.read())}clear(){try{E(this.storageKey)}catch(t){}}destroy(){if(this.onlineHandler){try{window.removeEventListener("online",this.onlineHandler)}catch(t){}this.onlineHandler=null}}installOnlineListener(){if("undefined"==typeof window)return;const t=()=>{this.flush()};try{window.addEventListener("online",t),this.onlineHandler=t}catch(t){}}read(){const t=q(this.storageKey);if(!t)return[];try{const n=JSON.parse(t);return Array.isArray(n)?n.filter(t=>Array.isArray(t)&&t.length>0):[]}catch(t){return[]}}write(t){0!==t.length?z(this.storageKey,JSON.stringify(t)):E(this.storageKey)}}function pt(t){let n=0;for(const e of t)n+=e.length;return n}class mt{constructor(t){Object.defineProperty(this,"config",{enumerable:!0,configurable:!0,writable:!0,value:t}),Object.defineProperty(this,"buffer",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"timer",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"destroyed",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"handlers",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"retryQueue",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.retryQueue=new vt({debug:t.debug,resend:t=>this.send(t)}),this.installPageLifecycleHandlers(),this.retryQueue.flush()}setConfig(t){this.config=Object.assign(Object.assign({},this.config),t)}enqueue(t){this.destroyed||(this.buffer.push(t),this.buffer.length>=this.config.flushAt?this.flush():this.timer||(this.timer=setTimeout(()=>{this.timer=null,this.flush()},this.config.flushInterval)))}flush(){if(this.timer&&(clearTimeout(this.timer),this.timer=null),0===this.buffer.length)return Promise.resolve();const t=this.buffer;return this.buffer=[],this.send(t)}bufferedCount(){return this.buffer.length}destroy(){this.destroyed||(this.destroyed=!0,this.timer&&(clearTimeout(this.timer),this.timer=null),this.uninstallPageLifecycleHandlers(),this.retryQueue.destroy())}send(t){try{return this.config.useBatch?this.sendBatch(t):Promise.all(t.map(t=>this.sendSingle(t))).then(()=>{})}catch(t){return this.config.debug&&console.warn("[cnv-track] send failed synchronously; dropped batch",t),Promise.resolve()}}sendBatch(t){var n;const e=st(),r={batch:t.map(t=>bt(t,e)),context:Object.assign(Object.assign({},null!==(n=this.config.batchContext)&&void 0!==n?n:{}),{projectId:this.config.projectId,sentAt:e}),sentAt:e};return this.post(this.batchUrl(),r,t)}sendSingle(t){const n=bt(t,st());return this.post(this.singleUrl(t.type),n,[t])}batchUrl(){return this.config.endpoint+this.config.batchPath+"?projectId="+encodeURIComponent(this.config.projectId)}singleUrl(t){const n=this.config.singlePath.replace("{type}",t);return this.config.endpoint+n+"?projectId="+encodeURIComponent(this.config.projectId)}post(t,n,e){const r=JSON.stringify(n),o=((t,n)=>{try{return new Blob([t],{type:n})}catch(t){return null}})(r,this.config.contentType),i=o?o.size:(t=>{try{return new Blob([t]).size}catch(n){return t.length}})(r),c=i>65536?null:e;return c&&"undefined"!=typeof navigator&&!1===navigator.onLine?(this.retryQueue.stash(c),this.config.debug&&console.log("[cnv-track] offline; queued for retry",t),Promise.resolve()):o&&this.sendViaBeacon(t,o)?(this.config.debug&&console.log("[cnv-track] beacon",t),Promise.resolve()):this.sendViaFetch(t,r,c)}sendViaBeacon(t,n){if("undefined"==typeof navigator||"function"!=typeof navigator.sendBeacon)return!1;if(n.size>65536)return!1;try{return navigator.sendBeacon(t,n)}catch(t){return!1}}sendViaFetch(t,n,e){return"function"!=typeof fetch?(this.config.debug&&console.warn("[cnv-track] no transport available; queued for retry"),e&&this.retryQueue.stash(e),Promise.resolve()):fetch(t,{method:"POST",headers:{"Content-Type":this.config.contentType},body:n,keepalive:!0,credentials:"omit",mode:"cors"}).then(n=>{this.config.debug&&console.log("[cnv-track] fetch flushed",t,n.status)}).catch(n=>{this.config.debug&&console.warn("[cnv-track] flush failed; queued for retry",t,n),e&&this.retryQueue.stash(e)})}installPageLifecycleHandlers(){if("undefined"==typeof window||"undefined"==typeof document)return;const t=()=>{this.flush()},n=()=>{"hidden"===document.visibilityState&&this.flush()};try{window.addEventListener("pagehide",t),document.addEventListener("visibilitychange",n),this.handlers={pagehide:t,visibility:n}}catch(t){}}uninstallPageLifecycleHandlers(){if(this.handlers){try{window.removeEventListener("pagehide",this.handlers.pagehide),document.removeEventListener("visibilitychange",this.handlers.visibility)}catch(t){}this.handlers=null}}}function bt(t,n){return Object.assign(Object.assign({},t),{sentAt:n})}const gt="_cnv_uid",wt="_cnv_traits";function xt(){return $(gt)||q(gt)}const jt={endpoint:"https://tracking.cnvcdp.com/js/v1",batchPath:"/batch",singlePath:"/{type}",useBatch:!0,contentType:"text/plain",debug:!1,allowAdTracking:!0,cookieMaxAgeDays:730,sessionTimeoutMinutes:30,flushAt:20,flushInterval:5e3,autoPageview:!0,autotrack:!1,integrations:{},remoteConfig:W(void 0)},kt={analytics:!0,marketing:!0};function Ot(t,n){if(!Array.isArray(n)||0===n.length)return;const e=n;try{switch(e[0]){case"init":t.init(e[1],e[2]);break;case"pageview":t.pageview(e[1],e[2]);break;case"page":t.page(e[1],e[2]);break;case"screen":t.screen(e[1],e[2]);break;case"track":t.track(e[1],e[2]);break;case"identify":t.identify(e[1],e[2]);break;case"alias":t.alias(e[1],e[2]);break;case"group":t.group(e[1],e[2]);break;case"reset":t.reset();break;case"flush":t.flush();break;case"consent":t.consent(e[1]);break;case"set":t.set(e[1])}}catch(t){}}const St=/^(https:|zalo:)/i;class At extends Error{constructor(t){super(`loginWithZalo() thất bại: ${t}`),Object.defineProperty(this,"reason",{enumerable:!0,configurable:!0,writable:!0,value:t}),this.name="ZaloQrLoginError"}}function Tt(t,n,e,r){return`${t}${n}?${new URLSearchParams(Object.assign({projectId:e},r)).toString()}`}function It(t,n){return C(this,void 0,void 0,function*(){var e,r,o;if(!t.projectId||!t.endpoint)throw new At("not-initialized");if(!t.zaloQrLoginEnabled)throw new At("disabled");if(!t.consentGranted)throw new At("consent-required");const i={preferSse:null===(e=null==n?void 0:n.preferSse)||void 0===e||e,pollIntervalMs:null!==(r=null==n?void 0:n.pollIntervalMs)&&void 0!==r?r:2e3,autoIdentify:null===(o=null==n?void 0:n.autoIdentify)||void 0===o||o},c=t.projectId,u=t.endpoint,l=yield function(t,n){return C(this,void 0,void 0,function*(){const e="undefined"!=typeof AbortController?new AbortController:null,r=e?setTimeout(()=>e.abort(),8e3):null;let o;try{o=yield fetch(Tt(t,"/zalo-qr/session",n),{method:"POST",credentials:"omit",mode:"cors",signal:e?e.signal:void 0})}catch(t){throw new At("network")}finally{r&&clearTimeout(r)}if(!o.ok)throw new At(401===(i=o.status)?"invalid-project-key":403===i?"project-suspended":"network");var i;return(t=>{const n=t;if(!n||"string"!=typeof n.sessionToken||!n.sessionToken||"string"!=typeof n.miniAppDeepLink||!St.test(n.miniAppDeepLink)||"number"!=typeof n.expiresInSeconds||!Number.isFinite(n.expiresInSeconds)||n.expiresInSeconds<=0)throw new At("network");return{sessionToken:n.sessionToken,miniAppDeepLink:n.miniAppDeepLink,expiresInSeconds:n.expiresInSeconds}})(yield o.json())})}(u,c),s=((t,n,e,r,o)=>{let i=!1,c=null,u=null,l=null,s=null,a=null;const f=()=>{c&&(c.close(),c=null),null!==u&&(clearInterval(u),u=null),null!==l&&(clearTimeout(l),l=null),null!==s&&(clearTimeout(s),s=null)};return{promise:new Promise((d,h)=>{a=h;const y=t=>{i||(i=!0,f(),t())},v=t=>{"success"===t.status?y(()=>d((t=>({contactId:t.contactId,fullName:t.fullName,level:t.level,xp:t.xp}))(t))):"denied"===t.status?y(()=>h(new At("denied"))):"expired"===t.status&&y(()=>h(new At("expired")))},p=()=>{null!==u||i||(u=setInterval(()=>{fetch(Tt(t,"/zalo-qr/status",n,{sessionToken:e}),{method:"GET",credentials:"omit",mode:"cors"}).then(t=>404===t.status?v({status:"expired"}):t.ok?t.json().then(t=>v(t)):void 0).catch(()=>{})},o.pollIntervalMs))};if(o.preferSse&&"undefined"!=typeof EventSource)try{c=new EventSource(Tt(t,"/zalo-qr/stream",n,{sessionToken:e})),c.addEventListener("success",t=>{try{v(JSON.parse(t.data))}catch(t){}}),c.addEventListener("denied",()=>v({status:"denied"})),c.onerror=()=>{null!==s||i||(s=setTimeout(()=>{s=null,i||(c&&(c.close(),c=null),p())},3e3))}}catch(t){p()}else p();l=setTimeout(()=>{y(()=>h(new At("expired")))},1e3*r)}),cancel(){i||(i=!0,f(),null==a||a(new At("cancelled")))}}})(u,c,l.sessionToken,l.expiresInSeconds,i),a=s.promise.then(n=>{try{if(i.autoIdentify&&null!=n.contactId){const e=String(n.contactId),r=t.getUserId();null!=r&&r!==e?t.alias(e,r):t.identify(e,Object.assign(Object.assign(Object.assign({},n.fullName?{name:n.fullName}:{}),n.level?{level:n.level}:{}),null!=n.xp?{xp:n.xp}:{}))}}catch(t){}return n});return{sessionToken:l.sessionToken,qrPayload:l.miniAppDeepLink,expiresInSeconds:l.expiresInSeconds,result:a,cancel:s.cancel,retry(){return s.cancel(),It(t,n)}}})}const _t="0.2.0-beta.4",Pt="@cnv-vn/track",Mt=function(){let t=null,i=Object.assign({},jt),c=Object.assign({},kt),u=null,l=!1,s=null,a=null;function f(t){const n=Object.assign({},i);return t?(void 0!==t.endpoint&&(n.endpoint=(e=t.endpoint).endsWith("/")?e.slice(0,-1):e),void 0!==t.batchPath&&(n.batchPath=t.batchPath),void 0!==t.singlePath&&(n.singlePath=t.singlePath),void 0!==t.useBatch&&(n.useBatch=t.useBatch),void 0!==t.contentType&&(n.contentType=t.contentType),void 0!==t.debug&&(n.debug=t.debug),void 0!==t.allowAdTracking&&(n.allowAdTracking=t.allowAdTracking),void 0!==t.cookieDomain&&(n.cookieDomain=t.cookieDomain),void 0!==t.cookieMaxAgeDays&&(n.cookieMaxAgeDays=t.cookieMaxAgeDays),void 0!==t.sessionTimeoutMinutes&&(n.sessionTimeoutMinutes=t.sessionTimeoutMinutes),void 0!==t.flushAt&&(n.flushAt=t.flushAt),void 0!==t.flushInterval&&(n.flushInterval=t.flushInterval),void 0!==t.autoPageview&&(n.autoPageview=t.autoPageview),void 0!==t.autotrack&&(n.autotrack=t.autotrack),void 0!==t.integrations&&(n.integrations=t.integrations),void 0!==t.remoteConfig&&(n.remoteConfig=W(t.remoteConfig,i.remoteConfig)),n):n;var e}function d(){return u||(u=new mt({endpoint:i.endpoint,batchPath:i.batchPath,singlePath:i.singlePath,useBatch:i.useBatch,contentType:i.contentType,flushAt:i.flushAt,flushInterval:i.flushInterval,projectId:null!=t?t:"",debug:i.debug}),u)}function h(){var n;if(!t)return null;const e=((t={})=>{var n;const e={page:X(),screen:{width:K(()=>window.screen.width,0),height:K(()=>window.screen.height,0),density:K(()=>window.devicePixelRatio||1,1)},locale:K(()=>navigator.language||"",""),timezone:K(()=>Intl.DateTimeFormat().resolvedOptions().timeZone||"",""),userAgent:K(()=>navigator.userAgent||"",""),library:Y(t.library)},r=((t,n=!0)=>{const e=K(()=>window.location.search,"");if(!e)return;let r;try{r=new URLSearchParams(e)}catch(t){return}const o={};let i=!1;for(const[t,n]of H){const e=r.get(t);e&&e.length>0&&(o[n]=e,i=!0)}if(n){const t={};for(const n of V){const e=r.get(n);e&&e.length>0&&(t[n]=e)}Object.keys(t).length>0&&(o.clickIds=t,i=!0)}return i?o:void 0})(0,null===(n=t.allowAdTracking)||void 0===n||n);return r&&(e.campaign=r),e})({allowAdTracking:i.allowAdTracking});return c.analytics&&c.marketing||(e.consent=Object.assign({},c)),{anonymousId:ct({cookieDomain:i.cookieDomain,cookieMaxAgeDays:i.cookieMaxAgeDays}),sessionId:ht({cookieDomain:i.cookieDomain,timeoutMinutes:i.sessionTimeoutMinutes}),userId:null!==(n=xt())&&void 0!==n?n:void 0,context:e,projectId:t,integrations:Object.keys(i.integrations).length>0?i.integrations:void 0}}function y(t){i.debug&&console.warn(`[cnv-track] ${t}() called before init()`)}function v(t,n){try{const e=h();if(!e)return y("pageview");const r=((t,n,e)=>{const r=at("page",e);return t&&(r.name=t),r.properties=null!=n?n:{},r})(t,((t,n)=>{const e={};return t&&(t.url&&(e.url=t.url),t.path&&(e.path=t.path),t.title&&(e.title=t.title),t.referrer&&(e.referrer=t.referrer),t.search&&(e.search=t.search)),Object.assign(Object.assign({},e),null!=n?n:{})})(e.context.page,n),e);d().enqueue(r)}catch(t){}}function p(t,n){v(t,n)}function m(t,n){try{if("string"!=typeof t||0===t.length)return;const e=h();if(!e)return y("track");const r=((t,n,e)=>{const r=at("track",e);return r.event=t,r.properties=null!=n?n:{},r})(t,n,e);d().enqueue(r)}catch(t){}}return{get initialized(){return l},get projectId(){return t},get endpoint(){return i.endpoint},isZaloQrLoginEnabled:()=>!!t&&(t=>{const n=G(t);return!n||!1!==(null===(r=null==(e=n.envelope)?void 0:e.zaloQrLogin)||void 0===r?void 0:r.enabled);var e,r})(t),get consentGranted(){return c.analytics&&c.marketing},init(h,y){try{if(!h||"string"!=typeof h)return;if(i=f(y),(null==y?void 0:y.consent)&&(c=Object.assign(Object.assign({},c),y.consent)),t=h,u&&u.destroy(),u=null,d(),l=!0,ct({cookieDomain:i.cookieDomain,cookieMaxAgeDays:i.cookieMaxAgeDays}),ht({cookieDomain:i.cookieDomain,timeoutMinutes:i.sessionTimeoutMinutes}),i.autoPageview&&v(),s){try{s()}catch(t){}s=null}const b={page(t,n){return p(t,n)},track(t,n){return m(t,n)}};if(i.autotrack){let t=i.autotrack;i.remoteConfig.enabled&&"object"==typeof t&&t.buttonTracking&&(t=Object.assign(Object.assign({},t),{buttonTracking:void 0})),s=function(t,i){const c=void 0===(u=i)||!1===u?Object.assign(Object.assign({},D),{searchParams:P}):!0===u?Object.assign(Object.assign({},M),{searchParams:P}):{spa:null===(l=u.spa)||void 0===l||l,outboundClicks:null===(s=u.outboundClicks)||void 0===s||s,scroll:null===(a=u.scroll)||void 0===a||a,downloads:null===(f=u.downloads)||void 0===f||f,siteSearch:null===(d=u.siteSearch)||void 0===d||d,downloadExtensions:u.downloadExtensions,searchParams:null!==(h=u.searchParams)&&void 0!==h?h:P,buttonTracking:u.buttonTracking};var u,l,s,a,f,d,h;const y=[];let v=null;function p(n){if(c.siteSearch)try{const e=null!=n?n:(()=>{try{return"undefined"!=typeof location?location.href:""}catch(t){return""}})();if(e===v)return;v=e;const r=((t,n=P)=>{try{if(!t){if("undefined"==typeof location)return null;t=location.href}const e=t instanceof URL?t:new URL(t,(()=>{try{return"undefined"!=typeof location?location.href:"http://localhost/"}catch(t){return"http://localhost/"}})());if(!e.search)return null;for(const t of n){const n=e.searchParams.get(t);if(null===n)continue;const r=n.trim();if(0!==r.length)return{query:r,param:t}}return null}catch(t){return null}})(e,c.searchParams);r&&U(()=>t.track("Site Searched",{query:r.query,param:r.param}))}catch(t){}}if(c.outboundClicks||c.downloads){const i=(t=>{var i;if("undefined"==typeof document)return()=>{};const c=new Set((null!==(i=t.downloadExtensions)&&void 0!==i?i:n).map(t=>t.toLowerCase())),u=!!t.onOutbound,l=!!t.onDownload;if(!u&&!l)return()=>{};function s(n){var i,s;try{if(0!==n.button)return;if(n.defaultPrevented)return;const a=(t=>{const n="function"==typeof t.composedPath?t.composedPath():[];if(n.length>0)for(const t of n)if(e(t))return t;let r=t.target;for(;r;){if(e(r))return r;r=r.parentNode}return null})(n);if(!a)return;const f=a.getAttribute("href");if(!f)return;if(/^(javascript:|mailto:|tel:|sms:)/i.test(f))return;if(f.startsWith("#"))return;const d=(t=>{try{return new URL(t,location.href)}catch(t){return null}})(f);if(!d)return;let h=!1;if(l){const n=a.hasAttribute("download"),e=(t=>{const n=r(t),e=n.lastIndexOf(".");return e<=0||e===n.length-1?null:n.slice(e+1).toLowerCase()})(d.pathname);(n||e&&c.has(e))&&(h=!0,null===(i=t.onDownload)||void 0===i||i.call(t,{url:d.href,fileName:r(d.pathname),fileExtension:null!=e?e:"",text:o(a)}))}u&&!h&&d.host!==(()=>{try{return"undefined"!=typeof location?location.hostname:""}catch(t){return""}})()&&d.host&&(null===(s=t.onOutbound)||void 0===s||s.call(t,{url:d.href,host:d.host,text:o(a),target:a.target||"_self"}))}catch(t){}}try{document.addEventListener("click",s,!0)}catch(t){return()=>{}}return()=>{try{document.removeEventListener("click",s,!0)}catch(t){}}})({downloadExtensions:c.downloadExtensions,onOutbound:c.outboundClicks?n=>U(()=>t.track("Clicked",n)):void 0,onDownload:c.downloads?n=>U(()=>t.track("File Downloaded",n)):void 0});y.push(i)}c.buttonTracking&&c.buttonTracking.rules&&c.buttonTracking.rules.length>0&&y.push(w(t,c.buttonTracking));let m=null;if(c.scroll&&(m=(t=>{if("undefined"==typeof window||"undefined"==typeof document)return{destroy(){},reset(){}};let n=!1,e=null,r=!1;function o(){if(e=null,!r&&!n)try{const e=document.documentElement,r=document.body,o=Math.max(e?e.scrollHeight:0,r?r.scrollHeight:0),i=Math.max(e?e.clientHeight:0,window.innerHeight||0);if(o<=i)return n=!0,c(),void t(90);((window.scrollY||(e?e.scrollTop:0)||0)+i)/o>=.9&&(n=!0,c(),t(90))}catch(t){}}function i(){if(null===e)try{e=window.requestAnimationFrame(o)}catch(t){o()}}function c(){try{window.removeEventListener("scroll",i),null!==e&&window.cancelAnimationFrame(e),e=null}catch(t){}}try{window.addEventListener("scroll",i,{passive:!0})}catch(t){try{window.addEventListener("scroll",i)}catch(t){}}try{window.requestAnimationFrame(o)}catch(t){o()}return{destroy(){r=!0,c()},reset(){if(!r){n=!1;try{window.addEventListener("scroll",i,{passive:!0})}catch(t){try{window.addEventListener("scroll",i)}catch(t){}}try{window.requestAnimationFrame(o)}catch(t){o()}}}}})(n=>{U(()=>t.track("Scrolled",{percent:n}))}),y.push(()=>null==m?void 0:m.destroy())),c.spa){const n=[],e=function(){if("undefined"==typeof window||"undefined"==typeof history)return()=>{};let e=_();function r(){try{const r=_();if(r===e)return;e=r,(e=>{const r=setTimeout(()=>{const e=n.indexOf(r);-1!==e&&n.splice(e,1),U(()=>t.page())},0);n.push(r),null==m||m.reset(),p(e)})(r)}catch(t){}}const o=history.pushState,i=history.replaceState,c=!0===o[I],u=!0===i[I];if(!c){function a(...t){o.apply(this,t),r()}a[I]=!0,history.pushState=a}if(!u){function f(...t){i.apply(this,t),r()}f[I]=!0,history.replaceState=f}const l=()=>r(),s=()=>r();try{window.addEventListener("popstate",l),window.addEventListener("hashchange",s)}catch(d){}return()=>{try{window.removeEventListener("popstate",l),window.removeEventListener("hashchange",s)}catch(t){}try{!c&&history.pushState[I]&&(history.pushState=o),!u&&history.replaceState[I]&&(history.replaceState=i)}catch(t){}}}();y.push(()=>{for(let t=0;t<n.length;t++)clearTimeout(n[t]);n.length=0,e()})}return p(),()=>{for(;y.length>0;){const t=y.pop();try{null==t||t()}catch(t){}}v=null}}(b,t)}if(a){try{a()}catch(t){}a=null}if(i.remoteConfig.enabled&&t){const n=t=>{if(a){try{a()}catch(t){}a=null}t&&t.rules&&t.rules.length>0&&(a=w(b,t))},e=(t=>{const n=G(t);return n?Q(n.envelope):null})(t);e&&n(e),function(t){return C(this,void 0,void 0,function*(){if(!t.projectId)return{status:"error"};const n=G(t.projectId);if(n&&Date.now()-n.fetchedAt<t.ttlMs)return{status:"unchanged"};const e=yield function(t){return C(this,void 0,void 0,function*(){var n;if("function"!=typeof fetch)return null;const e=t.endpoint+t.path+"?projectId="+encodeURIComponent(t.projectId),r="undefined"!=typeof AbortController?new AbortController:null,o=r?setTimeout(()=>r.abort(),t.timeoutMs):null;try{const o={};t.etag&&(o["If-None-Match"]=t.etag);const i=yield fetch(e,{method:"GET",headers:o,credentials:"omit",mode:"cors",signal:r?r.signal:void 0});if(304===i.status)return{envelope:null,etag:null!==(n=t.etag)&&void 0!==n?n:"",notModified:!0};if(!i.ok)return null;const c=i.headers&&"function"==typeof i.headers.get?i.headers.get("ETag"):null;return{envelope:yield i.json(),etag:null!=c?c:"",notModified:!1}}catch(t){return null}finally{o&&clearTimeout(o)}})}({endpoint:t.endpoint,path:t.path,projectId:t.projectId,timeoutMs:t.timeoutMs,etag:null==n?void 0:n.etag});return e?e.notModified?(n&&F(t.projectId,n.etag,n.envelope),{status:"unchanged"}):e.envelope?(F(t.projectId,e.etag,e.envelope),{status:"updated",buttonTracking:Q(e.envelope)}):{status:"error"}:{status:"error"}})}({endpoint:i.endpoint,path:i.remoteConfig.path,projectId:t,timeoutMs:i.remoteConfig.timeoutMs,ttlMs:i.remoteConfig.ttlMs}).then(t=>{"updated"===t.status&&n(t.buttonTracking)}).catch(()=>{})}}catch(t){}},pageview:v,page:p,screen(t,n){try{const e=h();if(!e)return y("screen");const r=((t,n,e)=>{const r=at("screen",e);return t&&(r.name=t),r.properties=null!=n?n:{},r})(t,n,e);d().enqueue(r)}catch(t){}},track:m,identify(t,n){try{if("string"!=typeof t||0===t.length)return;((t,n,e={})=>{var r,o;if(t&&(L(gt,t,{domain:e.cookieDomain,maxAgeDays:null!==(r=e.cookieMaxAgeDays)&&void 0!==r?r:730,sameSite:"Lax"}),z(gt,t),null!=n)){const t=null!==(o=(()=>{const t=q(wt);if(!t)return null;try{const n=JSON.parse(t);return n&&"object"==typeof n&&!Array.isArray(n)?n:null}catch(t){return null}})())&&void 0!==o?o:{},e=Object.assign(Object.assign({},t),n);try{z(wt,JSON.stringify(e))}catch(t){}}})(t,n,{cookieDomain:i.cookieDomain,cookieMaxAgeDays:i.cookieMaxAgeDays});const e=h();if(!e)return y("identify");const r=((t,n,e)=>{var r;const o=at("identify",e);return t&&(o.userId=t),o.traits=null!==(r=n)&&void 0!==r?r:{},o})(t,n,e);d().enqueue(r)}catch(t){}},alias(t,n){try{if("string"!=typeof t||0===t.length)return;const e=h();if(!e)return y("alias");const r=((t,n,e)=>{const r=at("alias",e);return t&&(r.userId=t),r.previousId=null!=n?n:e.anonymousId,r})(t,n,e);d().enqueue(r)}catch(t){}},group(t,n){try{if("string"!=typeof t||0===t.length)return;const e=h();if(!e)return y("group");const r=((t,n,e)=>{const r=at("group",e);return r.groupId=t,r.traits=null!=n?n:{},r})(t,n,e);d().enqueue(r)}catch(t){}},reset(){try{((t={})=>{((t,n={})=>{var e;if(!N)return!1;try{let r=`${encodeURIComponent(t)}=`;return r+=`; path=${null!==(e=n.path)&&void 0!==e?e:"/"}`,n.domain&&(r+=`; domain=${n.domain}`),r+="; max-age=0",r+="; expires=Thu, 01 Jan 1970 00:00:00 GMT",document.cookie=r,null===$(t)}catch(t){return!1}})(gt,{domain:t.cookieDomain}),E(gt),E(wt)})({cookieDomain:i.cookieDomain}),((t={})=>{ut(et(),t)})({cookieDomain:i.cookieDomain,cookieMaxAgeDays:i.cookieMaxAgeDays}),((t={})=>{yt({id:et(),lastActivity:Date.now()},t)})({cookieDomain:i.cookieDomain,timeoutMinutes:i.sessionTimeoutMinutes})}catch(t){}},flush(){try{u&&u.flush()}catch(t){}},consent(t){try{c=Object.assign(Object.assign({},c),t)}catch(t){}},set(t){try{i=f(t),t.consent&&(c=Object.assign(Object.assign({},c),t.consent)),u&&u.setConfig({endpoint:i.endpoint,batchPath:i.batchPath,singlePath:i.singlePath,useBatch:i.useBatch,contentType:i.contentType,flushAt:i.flushAt,flushInterval:i.flushInterval,debug:i.debug})}catch(t){}},destroy(){if(s){try{s()}catch(t){}s=null}if(a){try{a()}catch(t){}a=null}u&&u.destroy(),u=null,l=!1,t=null,i=Object.assign({},jt),c=Object.assign({},kt)}}}();function Dt(t){return It({projectId:Mt.projectId,endpoint:Mt.endpoint,zaloQrLoginEnabled:Mt.isZaloQrLoginEnabled(),consentGranted:Mt.consentGranted,identify:Mt.identify,alias:Mt.alias,getUserId:xt},t)}"undefined"!=typeof window&&(t=>{if("undefined"==typeof window)return()=>{};const n=window.cnvQ;if(n&&n.__loaded)return()=>{};const e=window.cnvQ=null!=n?n:[],r=e.splice(0,e.length);e.push.bind(e),e.push=(...n)=>{for(const e of n)Ot(t,e);return e.length},e.__loaded=!0;for(const n of r)Ot(t,n)})(Mt);const Ut=Object.assign(Mt,{version:_t,name:Pt,schemaVersion:lt,loginWithZalo:Dt});t.NAME=Pt,t.SCHEMA_VERSION=lt,t.VERSION=_t,t.ZaloQrLoginError=At,t.default=Ut,t.loginWithZalo=Dt,Object.defineProperty(t,"t",{value:!0})}(this.cnvTrack=this.cnvTrack||{});
@@ -1,6 +0,0 @@
1
- /*!
2
- * @cnv-vn/track v0.2.0-beta.4
3
- * (c) 2026 CNV
4
- * Released under the UNLICENSED license.
5
- */
6
- var t,n;t=this,n=function(t){const n=["pdf","doc","docx","xls","xlsx","ppt","pptx","txt","csv","rtf","zip","rar","7z","tar","gz","mp3","mp4","mov","wav","avi","mkv","dmg","exe","pkg","apk","msi","svg"];function e(t){return!!t&&"object"==typeof t&&1===t.nodeType&&"A"===t.tagName}function r(t){const n=t.lastIndexOf("/");return-1===n?t:t.slice(n+1)}function o(t){var n,e,r;let o=(null!==(n=t.textContent)&&void 0!==n?n:"").trim();return o||(o=(null!==(e=t.getAttribute("aria-label"))&&void 0!==e?e:"").trim()),o||(o=(null!==(r=t.getAttribute("title"))&&void 0!==r?r:"").trim()),o.length>200?o.slice(0,200):o}const i=200;function c(t){let n="";try{n=(t.textContent||"").replace(/\s+/g," ").trim(),n||(n=(t.getAttribute("aria-label")||"").trim()),n||(n=(t.getAttribute("title")||"").trim()),n=n.normalize("NFC")}catch(t){return""}return n.length>i?n.slice(0,i):n}function u(t){const n=!1!==t.caseInsensitive;if("regex"===t.mode)return{mode:"regex",needle:t.value,ci:n,re:m(t.value,n)};const e=t.value.normalize("NFC");return{mode:t.mode,needle:n?e.toLowerCase():e,ci:n,re:null}}function l(t,n){try{return t.matches(n)}catch(t){return!1}}function s(t){try{if("A"===t.tagName){const n=t.getAttribute("href");return n?b(n):null}const n=t.getAttribute("formaction");if(n)return b(n);const e=t.getAttribute("data-href");if(e)return b(e);const r=t.closest("form");if(r){const t=r.getAttribute("action");if(t)return b(t)}return null}catch(t){return null}}function a(t){return"regex"===t.mode?{mode:"regex",needle:t.value,re:m(t.value,!0)}:{mode:t.mode,needle:t.value.toLowerCase(),re:null}}function f(t){if("startsWith"===t.mode)return{mode:"startsWith",needle:t.value,re:null};const n="glob"===t.mode?"^"+t.value.replace(/[.+^${}()|[\]\\?]/g,"\\$&").replace(/\*/g,".*")+"$":t.value;return{mode:t.mode,needle:t.value,re:m(n,!1)}}function d(t,n){return"startsWith"===t.mode?0===n.indexOf(t.needle):!t.re||g(t.re,n)}const h=/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,y=/\+?\d[\d\s().-]{7,}\d/g;function v(t){if(!t)return t;try{return t.replace(h,"[email]").replace(y,"[phone]")}catch(n){return t}}function p(t){return!!t&&"object"==typeof t&&1===t.nodeType}function b(t){try{return new URL(t,location.href).href}catch(n){return t}}function m(t,n){try{return!t||t.length>1e3?null:new RegExp(t,n?"i":"")}catch(t){return null}}function g(t,n){try{return t.test(n)}catch(t){return!1}}function w(t,n){if("undefined"==typeof document)return()=>{};const e=(t=>{const n=t.globalThrottle||{},e=[],r=t.rules||[];for(let t=0;t<r.length;t++){const o=r[t];if(!o||!1===o.enabled)continue;if(!o.match||!o.event)continue;const i=o.match,c=o.throttle||{};e.push({rule:o,elementSpec:x(o),selector:i.selector||null,text:i.text?u(i.text):null,dest:i.destinationUrl?a(i.destinationUrl):null,urlScope:o.urlScope?f(o.urlScope):null,dedupeWindowMs:T(c.dedupeWindowMs,T(n.dedupeWindowMs,500)),maxPerPageview:T(c.maxPerPageview,T(n.maxPerPageview,1/0)),samplingRate:A(T(c.samplingRate,T(n.samplingRate,1)))})}return e.sort((t,n)=>(t.rule.priority||0)-(n.rule.priority||0)),e})(n);if(0===e.length)return()=>{};const r=new WeakMap;let o=0;const i=t=>{let n=r.get(t);return void 0===n&&(n=++o,r.set(t,n)),String(n)},c=new Map,l=new Map;let s=S();function h(n){try{if(0!==n.button)return;const r=S();r!==s&&(s=r,l.clear(),c.clear());const o=(t=>{const n=[];try{const e="function"==typeof t.composedPath?t.composedPath():[];if(e&&e.length>0){for(const t of e)p(t)&&n.push(t);return n}let r=t.target;for(;r;)p(r)&&n.push(r),r=r.parentNode}catch(t){}return n})(n);if(0===o.length)return;const u=(()=>{try{return"undefined"!=typeof location?location.pathname+location.search:""}catch(t){return""}})();for(let r=0;r<e.length;r++){const s=e[r];if(s.urlScope&&!d(s.urlScope,u))continue;let a=null;for(let t=0;t<o.length;t++)if(j(s,o[t])){a=o[t];break}if(!a)continue;const f=s.rule.id;if((l.get(f)||0)>=s.maxPerPageview)return;const h=f+"#"+i(a),y=Date.now(),v=c.get(h);if(void 0!==v&&y-v<s.dedupeWindowMs)return;if(s.samplingRate<1&&Math.random()>=s.samplingRate)return;c.set(h,y),l.set(f,(l.get(f)||0)+1);const p=k(s.rule,a,n);return void O(()=>t.track("Clicked",p))}}catch(t){}}try{document.addEventListener("click",h,!0)}catch(t){return()=>{}}return()=>{try{document.removeEventListener("click",h,!0)}catch(t){}c.clear(),l.clear()}}function x(t){const n=t.match;return n.element?n.element:n.selector||n.id||n.dataAttr||n.classes&&n.classes.length>0||n.destinationUrl?"any":void 0}function j(t,n){if(!((t,n)=>{if(!n)return(t=>{const n=t.tagName;if("BUTTON"===n||"A"===n)return!0;if("INPUT"===n){const n=(t.getAttribute("type")||"").toLowerCase();return"submit"===n||"button"===n||"reset"===n}return"button"===t.getAttribute("role")})(t);if("any"===n)return!0;if("button"===n){const n=t.tagName;if("BUTTON"===n)return!0;if("INPUT"===n){const n=(t.getAttribute("type")||"").toLowerCase();return"submit"===n||"button"===n||"reset"===n}return"button"===t.getAttribute("role")}return"link"===n?"A"===t.tagName:l(t,n)})(n,t.elementSpec))return!1;const e=t.rule.match;return!(t.selector&&!l(n,t.selector)||void 0!==e.id&&!((t,n)=>t.id===n)(n,e.id)||e.classes&&e.classes.length>0&&!((t,n)=>{try{for(let e=0;e<n.length;e++)if(!t.classList.contains(n[e]))return!1;return!0}catch(t){return!1}})(n,e.classes)||e.dataAttr&&!((t,n,e)=>{try{return!!t.hasAttribute(n)&&(void 0===e||t.getAttribute(n)===e)}catch(t){return!1}})(n,e.dataAttr.name,e.dataAttr.value)||t.text&&!((t,n)=>{const e=c(t);if("regex"===n.mode)return!!n.re&&g(n.re,e);const r=n.ci?e.toLowerCase():e;return"exact"===n.mode?r===n.needle:"startsWith"===n.mode?0===r.indexOf(n.needle):-1!==r.indexOf(n.needle)})(n,t.text)||t.dest&&!((t,n)=>{const e=s(t);if(!e)return!1;if("regex"===n.mode)return!!n.re&&g(n.re,e);if("domain"===n.mode)try{return new URL(e).host.toLowerCase()===n.needle}catch(t){return!1}const r=e.toLowerCase();return"exact"===n.mode?r===n.needle:"startsWith"===n.mode?0===r.indexOf(n.needle):-1!==r.indexOf(n.needle)})(n,t.dest))}function k(t,n,e){const r={},o=t.event.staticProps;if(o)for(const t of Object.keys(o))r[t]=o[t];const u=t.capture;if(u)try{if(u.text){const t=v(c(n));t&&(r.text=t)}if(u.href){const t=s(n);t&&(r.href=t)}if(u.elementId&&n.id&&(r.element_id=n.id),u.classes&&(r.element_classes=Array.from(n.classList)),u.dataAttrs&&u.dataAttrs.length>0)for(let t=0;t<u.dataAttrs.length;t++){const e=u.dataAttrs[t],o=n.getAttribute(e);null!==o&&(r[e]=v(o))}if(u.valueFrom){const t=((t,n)=>{try{const e=t.querySelector(n.selector)||(t.parentElement?t.parentElement.querySelector(n.selector):null);if(!e)return null;const r=n.attr?e.getAttribute(n.attr):e.textContent||"";if(null===r)return null;const o=v(r.replace(/\s+/g," ").trim());return o.length>i?o.slice(0,i):o}catch(t){return null}})(n,u.valueFrom);null!==t&&(r[u.valueFrom.as]=t)}u.selectorPath&&(r.selector_path=((t,n=5)=>{try{const e=[];let r=t,o=0;for(;r&&1===r.nodeType&&o<n;){let t=r.tagName.toLowerCase();if(r.id){e.unshift(t+"#"+r.id);break}const n=Array.from(r.classList).slice(0,2).join(".");n&&(t+="."+n),e.unshift(t),r=r.parentElement,o++}return e.join(" > ")}catch(t){return""}})(n)),u.position&&(r.x=e.clientX,r.y=e.clientY)}catch(t){}return r.rule_id=t.id,t.name&&(r.rule_name=t.name),t.event&&t.event.name&&(r.event_name=t.event.name),r.tag=n.tagName.toLowerCase(),r}function O(t){try{t()}catch(t){}}function S(){try{return"undefined"!=typeof location?location.href:""}catch(t){return""}}function T(t,n){return"number"!=typeof t||isNaN(t)?n:t}function A(t){return t<0?0:t>1?1:t}const I="__cnvPatched";function _(){try{return"undefined"!=typeof location?location.href:""}catch(t){return""}}const P=["q","s","query","search","keyword"],M={spa:!0,outboundClicks:!0,scroll:!0,downloads:!0,siteSearch:!0},D={spa:!1,outboundClicks:!1,scroll:!1,downloads:!1,siteSearch:!1};function U(t){try{t()}catch(t){}}function C(t,n,e,r){return new(e||(e=Promise))((o,i)=>{function c(t){try{l(r.next(t))}catch(t){i(t)}}function u(t){try{l(r.throw(t))}catch(t){i(t)}}function l(t){var n;t.done?o(t.value):(n=t.value,n instanceof e?n:new e(t=>{t(n)})).then(c,u)}l((r=r.apply(t,n||[])).next())})}"function"==typeof SuppressedError&&SuppressedError;const N="undefined"!=typeof window&&"undefined"!=typeof document;function $(t){if(!N)return null;try{const n=document.cookie;if(!n)return null;const e=encodeURIComponent(t),r=n.split(";");for(let n=0;n<r.length;n++){const o=r[n].indexOf("=");if(o<0)continue;const i=r[n].slice(0,o).trim();if(i===e||i===t)try{return decodeURIComponent(r[n].slice(o+1))}catch(t){return r[n].slice(o+1)}}return null}catch(t){return null}}function L(t,n,e={}){var r,o,i;if(!N)return!1;try{let c=`${encodeURIComponent(t)}=${encodeURIComponent(n)}`;if(c+=`; path=${null!==(r=e.path)&&void 0!==r?r:"/"}`,e.domain&&(c+=`; domain=${e.domain}`),"number"==typeof e.maxAgeDays){const t=Math.floor(86400*e.maxAgeDays);c+=`; max-age=${t}`,c+=`; expires=${new Date(Date.now()+1e3*t).toUTCString()}`}return c+=`; SameSite=${null!==(o=e.sameSite)&&void 0!==o?o:"Lax"}`,(null!==(i=e.secure)&&void 0!==i?i:"undefined"!=typeof location&&"https:"===location.protocol)&&(c+="; Secure"),document.cookie=c,$(t)===n}catch(t){return!1}}function R(){if(!N)return!1;try{const t="__cnv_probe__";return localStorage.setItem(t,"1"),localStorage.removeItem(t),!0}catch(t){return!1}}function q(t){if(!R())return null;try{return localStorage.getItem(t)}catch(t){return null}}function z(t,n){if(!R())return!1;try{return localStorage.setItem(t,n),!0}catch(t){return!1}}function E(t){if(!R())return!1;try{return localStorage.removeItem(t),!0}catch(t){return!1}}function B(){if(!N)return!1;try{const t="__cnv_probe__";return sessionStorage.setItem(t,"1"),sessionStorage.removeItem(t),!0}catch(t){return!1}}const J={path:"/config",timeoutMs:4e3,ttlMs:3e5};function W(t,n){var e,r;const o=null!=n?n:Object.assign({enabled:!0},J);return void 0===t?Object.assign({},o):!0===t?Object.assign(Object.assign({},o),{enabled:!0}):!1===t?Object.assign(Object.assign({},o),{enabled:!1}):{enabled:null===(e=t.enabled)||void 0===e||e,path:null!==(r=t.path)&&void 0!==r?r:o.path,timeoutMs:"number"==typeof t.timeoutMs?t.timeoutMs:o.timeoutMs,ttlMs:"number"==typeof t.ttlMs?t.ttlMs:o.ttlMs}}function Z(t){return"_cnv_cfg_"+t}function G(t){const n=q(Z(t));if(!n)return null;try{const t=JSON.parse(n);return t&&"object"==typeof t&&t.envelope?t:null}catch(t){return null}}function F(t,n,e){try{const r={etag:n,envelope:e,fetchedAt:Date.now()};z(Z(t),JSON.stringify(r))}catch(t){}}function Q(t){const n=null==t?void 0:t.buttonTracking;if(!n||!1===n.enabled)return null;const e=Array.isArray(n.rules)?n.rules:[];return 0===e.length?null:{rules:e,globalThrottle:n.globalThrottle}}const V=["gclid","fbclid","ttclid","msclkid","dclid"],H=[["utm_source","source"],["utm_medium","medium"],["utm_campaign","name"],["utm_term","term"],["utm_content","content"],["utm_id","id"]];function K(t,n){try{return t()}catch(t){return n}}function X(){const t=K(()=>window.location.href,"");let n="",e="",r="";if(t)try{const o=new URL(t);n=o.pathname,e=o.search,r=o.hash}catch(t){}return{url:t,path:n,search:e,hash:r,title:K(()=>document.title,""),referrer:K(()=>document.referrer,"")}}function Y(t){var n,e;let r="@cnv-vn/track",o="0.0.0-dev";try{r="@cnv-vn/track"}catch(t){}try{o="0.2.0-beta.4"}catch(t){}return{name:null!==(n=null==t?void 0:t.name)&&void 0!==n?n:r,version:null!==(e=null==t?void 0:t.version)&&void 0!==e?e:o}}const tt="0123456789abcdef";function nt(t){return tt[t>>>4&15]+tt[15&t]}function et(){if("undefined"!=typeof crypto){if("function"==typeof crypto.randomUUID)return crypto.randomUUID();if("function"==typeof crypto.getRandomValues){const t=new Uint8Array(16);return crypto.getRandomValues(t),t[6]=15&t[6]|64,t[8]=63&t[8]|128,nt(t[0])+nt(t[1])+nt(t[2])+nt(t[3])+"-"+nt(t[4])+nt(t[5])+"-"+nt(t[6])+nt(t[7])+"-"+nt(t[8])+nt(t[9])+"-"+nt(t[10])+nt(t[11])+nt(t[12])+nt(t[13])+nt(t[14])+nt(t[15])}}return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,t=>{const n=16*Math.random()|0;return("x"===t?n:3&n|8).toString(16)})}const rt=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;function ot(t){return"string"==typeof t&&rt.test(t)}const it="_cnv_cid";function ct(t={}){const n=$(it),e=q(it);let r=null;return ot(n)?r=n:ot(e)&&(r=e),r||(r=et()),ut(r,t),r}function ut(t,n={}){var e;L(it,t,{domain:n.cookieDomain,maxAgeDays:null!==(e=n.cookieMaxAgeDays)&&void 0!==e?e:730,sameSite:"Lax"}),z(it,t)}const lt="1.0";function st(){return(new Date).toISOString()}function at(t,n){var e;const r=null!==(e=n.timestamp)&&void 0!==e?e:st(),o=Object.assign(Object.assign({},n.context),{projectId:n.projectId,schemaVersion:lt}),i={type:t,messageId:et(),anonymousId:n.anonymousId,timestamp:r,originalTimestamp:r,context:o};return n.userId&&(i.userId=n.userId),n.sessionId&&(i.sessionId=n.sessionId),n.integrations&&(i.integrations=n.integrations),i}const ft="_cnv_sid";function dt(t){if(!t)return null;const n=t.lastIndexOf(".");if(n<0)return null;const e=t.slice(0,n),r=Number(t.slice(n+1));return!ot(e)||!Number.isFinite(r)||r<=0?null:{id:e,lastActivity:r}}function ht(t={}){const n=Date.now(),e=(t=>{var n;return 6e4*(null!==(n=t.timeoutMinutes)&&void 0!==n?n:30)})(t),r=dt($(ft)),o=dt((t=>{if(!B())return null;try{return sessionStorage.getItem(t)}catch(t){return null}})(ft));let i=null;for(const t of[r,o])t&&(n-t.lastActivity>e||(!i||t.lastActivity>i.lastActivity)&&(i=t));const c=i?{id:i.id,lastActivity:n}:{id:et(),lastActivity:n};return yt(c,t),c.id}function yt(t,n={}){var e;const r=(t=>`${t.id}.${t.lastActivity}`)(t),o=null!==(e=n.timeoutMinutes)&&void 0!==e?e:30;L(ft,r,{domain:n.cookieDomain,maxAgeDays:o/1440,sameSite:"Lax"}),((t,n)=>{if(!B())return!1;try{return sessionStorage.setItem(t,n),!0}catch(t){return!1}})(ft,r)}class vt{constructor(t){var n,e;Object.defineProperty(this,"config",{enumerable:!0,configurable:!0,writable:!0,value:t}),Object.defineProperty(this,"storageKey",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"maxMessages",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"flushing",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"onlineHandler",{enumerable:!0,configurable:!0,writable:!0,value:null}),this.storageKey=null!==(n=t.storageKey)&&void 0!==n?n:"_cnv_rq",this.maxMessages=null!==(e=t.maxMessages)&&void 0!==e?e:100,this.installOnlineListener()}stash(t){if(t&&0!==t.length)try{const n=this.read();for(n.push(t);n.length>1&&pt(n)>this.maxMessages;)n.shift();this.write(n),this.config.debug&&console.log("[cnv-track] retry queued",t.length,"buffered",pt(n))}catch(t){}}flush(){if(this.flushing||"undefined"!=typeof navigator&&!1===navigator.onLine)return Promise.resolve();const t=this.read();if(0===t.length)return Promise.resolve();this.flushing=!0,this.write([]);const n=()=>{this.flushing=!1};return t.reduce((t,n)=>t.then(()=>this.config.resend(n)),Promise.resolve()).then(n,n)}size(){return pt(this.read())}clear(){try{E(this.storageKey)}catch(t){}}destroy(){if(this.onlineHandler){try{window.removeEventListener("online",this.onlineHandler)}catch(t){}this.onlineHandler=null}}installOnlineListener(){if("undefined"==typeof window)return;const t=()=>{this.flush()};try{window.addEventListener("online",t),this.onlineHandler=t}catch(t){}}read(){const t=q(this.storageKey);if(!t)return[];try{const n=JSON.parse(t);return Array.isArray(n)?n.filter(t=>Array.isArray(t)&&t.length>0):[]}catch(t){return[]}}write(t){0!==t.length?z(this.storageKey,JSON.stringify(t)):E(this.storageKey)}}function pt(t){let n=0;for(const e of t)n+=e.length;return n}class bt{constructor(t){Object.defineProperty(this,"config",{enumerable:!0,configurable:!0,writable:!0,value:t}),Object.defineProperty(this,"buffer",{enumerable:!0,configurable:!0,writable:!0,value:[]}),Object.defineProperty(this,"timer",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"destroyed",{enumerable:!0,configurable:!0,writable:!0,value:!1}),Object.defineProperty(this,"handlers",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"retryQueue",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.retryQueue=new vt({debug:t.debug,resend:t=>this.send(t)}),this.installPageLifecycleHandlers(),this.retryQueue.flush()}setConfig(t){this.config=Object.assign(Object.assign({},this.config),t)}enqueue(t){this.destroyed||(this.buffer.push(t),this.buffer.length>=this.config.flushAt?this.flush():this.timer||(this.timer=setTimeout(()=>{this.timer=null,this.flush()},this.config.flushInterval)))}flush(){if(this.timer&&(clearTimeout(this.timer),this.timer=null),0===this.buffer.length)return Promise.resolve();const t=this.buffer;return this.buffer=[],this.send(t)}bufferedCount(){return this.buffer.length}destroy(){this.destroyed||(this.destroyed=!0,this.timer&&(clearTimeout(this.timer),this.timer=null),this.uninstallPageLifecycleHandlers(),this.retryQueue.destroy())}send(t){try{return this.config.useBatch?this.sendBatch(t):Promise.all(t.map(t=>this.sendSingle(t))).then(()=>{})}catch(t){return this.config.debug&&console.warn("[cnv-track] send failed synchronously; dropped batch",t),Promise.resolve()}}sendBatch(t){var n;const e=st(),r={batch:t.map(t=>mt(t,e)),context:Object.assign(Object.assign({},null!==(n=this.config.batchContext)&&void 0!==n?n:{}),{projectId:this.config.projectId,sentAt:e}),sentAt:e};return this.post(this.batchUrl(),r,t)}sendSingle(t){const n=mt(t,st());return this.post(this.singleUrl(t.type),n,[t])}batchUrl(){return this.config.endpoint+this.config.batchPath+"?projectId="+encodeURIComponent(this.config.projectId)}singleUrl(t){const n=this.config.singlePath.replace("{type}",t);return this.config.endpoint+n+"?projectId="+encodeURIComponent(this.config.projectId)}post(t,n,e){const r=JSON.stringify(n),o=((t,n)=>{try{return new Blob([t],{type:n})}catch(t){return null}})(r,this.config.contentType),i=o?o.size:(t=>{try{return new Blob([t]).size}catch(n){return t.length}})(r),c=i>65536?null:e;return c&&"undefined"!=typeof navigator&&!1===navigator.onLine?(this.retryQueue.stash(c),this.config.debug&&console.log("[cnv-track] offline; queued for retry",t),Promise.resolve()):o&&this.sendViaBeacon(t,o)?(this.config.debug&&console.log("[cnv-track] beacon",t),Promise.resolve()):this.sendViaFetch(t,r,c)}sendViaBeacon(t,n){if("undefined"==typeof navigator||"function"!=typeof navigator.sendBeacon)return!1;if(n.size>65536)return!1;try{return navigator.sendBeacon(t,n)}catch(t){return!1}}sendViaFetch(t,n,e){return"function"!=typeof fetch?(this.config.debug&&console.warn("[cnv-track] no transport available; queued for retry"),e&&this.retryQueue.stash(e),Promise.resolve()):fetch(t,{method:"POST",headers:{"Content-Type":this.config.contentType},body:n,keepalive:!0,credentials:"omit",mode:"cors"}).then(n=>{this.config.debug&&console.log("[cnv-track] fetch flushed",t,n.status)}).catch(n=>{this.config.debug&&console.warn("[cnv-track] flush failed; queued for retry",t,n),e&&this.retryQueue.stash(e)})}installPageLifecycleHandlers(){if("undefined"==typeof window||"undefined"==typeof document)return;const t=()=>{this.flush()},n=()=>{"hidden"===document.visibilityState&&this.flush()};try{window.addEventListener("pagehide",t),document.addEventListener("visibilitychange",n),this.handlers={pagehide:t,visibility:n}}catch(t){}}uninstallPageLifecycleHandlers(){if(this.handlers){try{window.removeEventListener("pagehide",this.handlers.pagehide),document.removeEventListener("visibilitychange",this.handlers.visibility)}catch(t){}this.handlers=null}}}function mt(t,n){return Object.assign(Object.assign({},t),{sentAt:n})}const gt="_cnv_uid",wt="_cnv_traits";function xt(){return $(gt)||q(gt)}const jt={endpoint:"https://tracking.cnvcdp.com/js/v1",batchPath:"/batch",singlePath:"/{type}",useBatch:!0,contentType:"text/plain",debug:!1,allowAdTracking:!0,cookieMaxAgeDays:730,sessionTimeoutMinutes:30,flushAt:20,flushInterval:5e3,autoPageview:!0,autotrack:!1,integrations:{},remoteConfig:W(void 0)},kt={analytics:!0,marketing:!0};function Ot(t,n){if(!Array.isArray(n)||0===n.length)return;const e=n;try{switch(e[0]){case"init":t.init(e[1],e[2]);break;case"pageview":t.pageview(e[1],e[2]);break;case"page":t.page(e[1],e[2]);break;case"screen":t.screen(e[1],e[2]);break;case"track":t.track(e[1],e[2]);break;case"identify":t.identify(e[1],e[2]);break;case"alias":t.alias(e[1],e[2]);break;case"group":t.group(e[1],e[2]);break;case"reset":t.reset();break;case"flush":t.flush();break;case"consent":t.consent(e[1]);break;case"set":t.set(e[1])}}catch(t){}}const St=/^(https:|zalo:)/i;class Tt extends Error{constructor(t){super(`loginWithZalo() thất bại: ${t}`),Object.defineProperty(this,"reason",{enumerable:!0,configurable:!0,writable:!0,value:t}),this.name="ZaloQrLoginError"}}function At(t,n,e,r){return`${t}${n}?${new URLSearchParams(Object.assign({projectId:e},r)).toString()}`}function It(t,n){return C(this,void 0,void 0,function*(){var e,r,o;if(!t.projectId||!t.endpoint)throw new Tt("not-initialized");if(!t.zaloQrLoginEnabled)throw new Tt("disabled");if(!t.consentGranted)throw new Tt("consent-required");const i={preferSse:null===(e=null==n?void 0:n.preferSse)||void 0===e||e,pollIntervalMs:null!==(r=null==n?void 0:n.pollIntervalMs)&&void 0!==r?r:2e3,autoIdentify:null===(o=null==n?void 0:n.autoIdentify)||void 0===o||o},c=t.projectId,u=t.endpoint,l=yield function(t,n){return C(this,void 0,void 0,function*(){const e="undefined"!=typeof AbortController?new AbortController:null,r=e?setTimeout(()=>e.abort(),8e3):null;let o;try{o=yield fetch(At(t,"/zalo-qr/session",n),{method:"POST",credentials:"omit",mode:"cors",signal:e?e.signal:void 0})}catch(t){throw new Tt("network")}finally{r&&clearTimeout(r)}if(!o.ok)throw new Tt(401===(i=o.status)?"invalid-project-key":403===i?"project-suspended":"network");var i;return(t=>{const n=t;if(!n||"string"!=typeof n.sessionToken||!n.sessionToken||"string"!=typeof n.miniAppDeepLink||!St.test(n.miniAppDeepLink)||"number"!=typeof n.expiresInSeconds||!Number.isFinite(n.expiresInSeconds)||n.expiresInSeconds<=0)throw new Tt("network");return{sessionToken:n.sessionToken,miniAppDeepLink:n.miniAppDeepLink,expiresInSeconds:n.expiresInSeconds}})(yield o.json())})}(u,c),s=((t,n,e,r,o)=>{let i=!1,c=null,u=null,l=null,s=null,a=null;const f=()=>{c&&(c.close(),c=null),null!==u&&(clearInterval(u),u=null),null!==l&&(clearTimeout(l),l=null),null!==s&&(clearTimeout(s),s=null)};return{promise:new Promise((d,h)=>{a=h;const y=t=>{i||(i=!0,f(),t())},v=t=>{"success"===t.status?y(()=>d((t=>({contactId:t.contactId,fullName:t.fullName,level:t.level,xp:t.xp}))(t))):"denied"===t.status?y(()=>h(new Tt("denied"))):"expired"===t.status&&y(()=>h(new Tt("expired")))},p=()=>{null!==u||i||(u=setInterval(()=>{fetch(At(t,"/zalo-qr/status",n,{sessionToken:e}),{method:"GET",credentials:"omit",mode:"cors"}).then(t=>404===t.status?v({status:"expired"}):t.ok?t.json().then(t=>v(t)):void 0).catch(()=>{})},o.pollIntervalMs))};if(o.preferSse&&"undefined"!=typeof EventSource)try{c=new EventSource(At(t,"/zalo-qr/stream",n,{sessionToken:e})),c.addEventListener("success",t=>{try{v(JSON.parse(t.data))}catch(t){}}),c.addEventListener("denied",()=>v({status:"denied"})),c.onerror=()=>{null!==s||i||(s=setTimeout(()=>{s=null,i||(c&&(c.close(),c=null),p())},3e3))}}catch(t){p()}else p();l=setTimeout(()=>{y(()=>h(new Tt("expired")))},1e3*r)}),cancel(){i||(i=!0,f(),null==a||a(new Tt("cancelled")))}}})(u,c,l.sessionToken,l.expiresInSeconds,i),a=s.promise.then(n=>{try{if(i.autoIdentify&&null!=n.contactId){const e=String(n.contactId),r=t.getUserId();null!=r&&r!==e?t.alias(e,r):t.identify(e,Object.assign(Object.assign(Object.assign({},n.fullName?{name:n.fullName}:{}),n.level?{level:n.level}:{}),null!=n.xp?{xp:n.xp}:{}))}}catch(t){}return n});return{sessionToken:l.sessionToken,qrPayload:l.miniAppDeepLink,expiresInSeconds:l.expiresInSeconds,result:a,cancel:s.cancel,retry:()=>(s.cancel(),It(t,n))}})}const _t="0.2.0-beta.4",Pt="@cnv-vn/track",Mt=function(){let t=null,i=Object.assign({},jt),c=Object.assign({},kt),u=null,l=!1,s=null,a=null;function f(t){const n=Object.assign({},i);return t?(void 0!==t.endpoint&&(n.endpoint=(e=t.endpoint).endsWith("/")?e.slice(0,-1):e),void 0!==t.batchPath&&(n.batchPath=t.batchPath),void 0!==t.singlePath&&(n.singlePath=t.singlePath),void 0!==t.useBatch&&(n.useBatch=t.useBatch),void 0!==t.contentType&&(n.contentType=t.contentType),void 0!==t.debug&&(n.debug=t.debug),void 0!==t.allowAdTracking&&(n.allowAdTracking=t.allowAdTracking),void 0!==t.cookieDomain&&(n.cookieDomain=t.cookieDomain),void 0!==t.cookieMaxAgeDays&&(n.cookieMaxAgeDays=t.cookieMaxAgeDays),void 0!==t.sessionTimeoutMinutes&&(n.sessionTimeoutMinutes=t.sessionTimeoutMinutes),void 0!==t.flushAt&&(n.flushAt=t.flushAt),void 0!==t.flushInterval&&(n.flushInterval=t.flushInterval),void 0!==t.autoPageview&&(n.autoPageview=t.autoPageview),void 0!==t.autotrack&&(n.autotrack=t.autotrack),void 0!==t.integrations&&(n.integrations=t.integrations),void 0!==t.remoteConfig&&(n.remoteConfig=W(t.remoteConfig,i.remoteConfig)),n):n;var e}function d(){return u||(u=new bt({endpoint:i.endpoint,batchPath:i.batchPath,singlePath:i.singlePath,useBatch:i.useBatch,contentType:i.contentType,flushAt:i.flushAt,flushInterval:i.flushInterval,projectId:null!=t?t:"",debug:i.debug}),u)}function h(){var n;if(!t)return null;const e=((t={})=>{var n;const e={page:X(),screen:{width:K(()=>window.screen.width,0),height:K(()=>window.screen.height,0),density:K(()=>window.devicePixelRatio||1,1)},locale:K(()=>navigator.language||"",""),timezone:K(()=>Intl.DateTimeFormat().resolvedOptions().timeZone||"",""),userAgent:K(()=>navigator.userAgent||"",""),library:Y(t.library)},r=((t,n=!0)=>{const e=K(()=>window.location.search,"");if(!e)return;let r;try{r=new URLSearchParams(e)}catch(t){return}const o={};let i=!1;for(const[t,n]of H){const e=r.get(t);e&&e.length>0&&(o[n]=e,i=!0)}if(n){const t={};for(const n of V){const e=r.get(n);e&&e.length>0&&(t[n]=e)}Object.keys(t).length>0&&(o.clickIds=t,i=!0)}return i?o:void 0})(0,null===(n=t.allowAdTracking)||void 0===n||n);return r&&(e.campaign=r),e})({allowAdTracking:i.allowAdTracking});return c.analytics&&c.marketing||(e.consent=Object.assign({},c)),{anonymousId:ct({cookieDomain:i.cookieDomain,cookieMaxAgeDays:i.cookieMaxAgeDays}),sessionId:ht({cookieDomain:i.cookieDomain,timeoutMinutes:i.sessionTimeoutMinutes}),userId:null!==(n=xt())&&void 0!==n?n:void 0,context:e,projectId:t,integrations:Object.keys(i.integrations).length>0?i.integrations:void 0}}function y(t){i.debug&&console.warn(`[cnv-track] ${t}() called before init()`)}function v(t,n){try{const e=h();if(!e)return y("pageview");const r=((t,n,e)=>{const r=at("page",e);return t&&(r.name=t),r.properties=null!=n?n:{},r})(t,((t,n)=>{const e={};return t&&(t.url&&(e.url=t.url),t.path&&(e.path=t.path),t.title&&(e.title=t.title),t.referrer&&(e.referrer=t.referrer),t.search&&(e.search=t.search)),Object.assign(Object.assign({},e),null!=n?n:{})})(e.context.page,n),e);d().enqueue(r)}catch(t){}}function p(t,n){v(t,n)}function b(t,n){try{if("string"!=typeof t||0===t.length)return;const e=h();if(!e)return y("track");const r=((t,n,e)=>{const r=at("track",e);return r.event=t,r.properties=null!=n?n:{},r})(t,n,e);d().enqueue(r)}catch(t){}}return{get initialized(){return l},get projectId(){return t},get endpoint(){return i.endpoint},isZaloQrLoginEnabled(){return!!t&&(t=>{const n=G(t);return!n||!1!==(null===(r=null==(e=n.envelope)?void 0:e.zaloQrLogin)||void 0===r?void 0:r.enabled);var e,r})(t)},get consentGranted(){return c.analytics&&c.marketing},init(h,y){try{if(!h||"string"!=typeof h)return;if(i=f(y),(null==y?void 0:y.consent)&&(c=Object.assign(Object.assign({},c),y.consent)),t=h,u&&u.destroy(),u=null,d(),l=!0,ct({cookieDomain:i.cookieDomain,cookieMaxAgeDays:i.cookieMaxAgeDays}),ht({cookieDomain:i.cookieDomain,timeoutMinutes:i.sessionTimeoutMinutes}),i.autoPageview&&v(),s){try{s()}catch(t){}s=null}const m={page:(t,n)=>p(t,n),track:(t,n)=>b(t,n)};if(i.autotrack){let t=i.autotrack;i.remoteConfig.enabled&&"object"==typeof t&&t.buttonTracking&&(t=Object.assign(Object.assign({},t),{buttonTracking:void 0})),s=function(t,i){const c=void 0===(u=i)||!1===u?Object.assign(Object.assign({},D),{searchParams:P}):!0===u?Object.assign(Object.assign({},M),{searchParams:P}):{spa:null===(l=u.spa)||void 0===l||l,outboundClicks:null===(s=u.outboundClicks)||void 0===s||s,scroll:null===(a=u.scroll)||void 0===a||a,downloads:null===(f=u.downloads)||void 0===f||f,siteSearch:null===(d=u.siteSearch)||void 0===d||d,downloadExtensions:u.downloadExtensions,searchParams:null!==(h=u.searchParams)&&void 0!==h?h:P,buttonTracking:u.buttonTracking};var u,l,s,a,f,d,h;const y=[];let v=null;function p(n){if(c.siteSearch)try{const e=null!=n?n:(()=>{try{return"undefined"!=typeof location?location.href:""}catch(t){return""}})();if(e===v)return;v=e;const r=((t,n=P)=>{try{if(!t){if("undefined"==typeof location)return null;t=location.href}const e=t instanceof URL?t:new URL(t,(()=>{try{return"undefined"!=typeof location?location.href:"http://localhost/"}catch(t){return"http://localhost/"}})());if(!e.search)return null;for(const t of n){const n=e.searchParams.get(t);if(null===n)continue;const r=n.trim();if(0!==r.length)return{query:r,param:t}}return null}catch(t){return null}})(e,c.searchParams);r&&U(()=>t.track("Site Searched",{query:r.query,param:r.param}))}catch(t){}}if(c.outboundClicks||c.downloads){const i=(t=>{var i;if("undefined"==typeof document)return()=>{};const c=new Set((null!==(i=t.downloadExtensions)&&void 0!==i?i:n).map(t=>t.toLowerCase())),u=!!t.onOutbound,l=!!t.onDownload;if(!u&&!l)return()=>{};function s(n){var i,s;try{if(0!==n.button)return;if(n.defaultPrevented)return;const a=(t=>{const n="function"==typeof t.composedPath?t.composedPath():[];if(n.length>0)for(const t of n)if(e(t))return t;let r=t.target;for(;r;){if(e(r))return r;r=r.parentNode}return null})(n);if(!a)return;const f=a.getAttribute("href");if(!f)return;if(/^(javascript:|mailto:|tel:|sms:)/i.test(f))return;if(f.startsWith("#"))return;const d=(t=>{try{return new URL(t,location.href)}catch(t){return null}})(f);if(!d)return;let h=!1;if(l){const n=a.hasAttribute("download"),e=(t=>{const n=r(t),e=n.lastIndexOf(".");return e<=0||e===n.length-1?null:n.slice(e+1).toLowerCase()})(d.pathname);(n||e&&c.has(e))&&(h=!0,null===(i=t.onDownload)||void 0===i||i.call(t,{url:d.href,fileName:r(d.pathname),fileExtension:null!=e?e:"",text:o(a)}))}u&&!h&&d.host!==(()=>{try{return"undefined"!=typeof location?location.hostname:""}catch(t){return""}})()&&d.host&&(null===(s=t.onOutbound)||void 0===s||s.call(t,{url:d.href,host:d.host,text:o(a),target:a.target||"_self"}))}catch(t){}}try{document.addEventListener("click",s,!0)}catch(t){return()=>{}}return()=>{try{document.removeEventListener("click",s,!0)}catch(t){}}})({downloadExtensions:c.downloadExtensions,onOutbound:c.outboundClicks?n=>U(()=>t.track("Clicked",n)):void 0,onDownload:c.downloads?n=>U(()=>t.track("File Downloaded",n)):void 0});y.push(i)}c.buttonTracking&&c.buttonTracking.rules&&c.buttonTracking.rules.length>0&&y.push(w(t,c.buttonTracking));let b=null;if(c.scroll&&(b=(t=>{if("undefined"==typeof window||"undefined"==typeof document)return{destroy(){},reset(){}};let n=!1,e=null,r=!1;function o(){if(e=null,!r&&!n)try{const e=document.documentElement,r=document.body,o=Math.max(e?e.scrollHeight:0,r?r.scrollHeight:0),i=Math.max(e?e.clientHeight:0,window.innerHeight||0);if(o<=i)return n=!0,c(),void t(90);((window.scrollY||(e?e.scrollTop:0)||0)+i)/o>=.9&&(n=!0,c(),t(90))}catch(t){}}function i(){if(null===e)try{e=window.requestAnimationFrame(o)}catch(t){o()}}function c(){try{window.removeEventListener("scroll",i),null!==e&&window.cancelAnimationFrame(e),e=null}catch(t){}}try{window.addEventListener("scroll",i,{passive:!0})}catch(t){try{window.addEventListener("scroll",i)}catch(t){}}try{window.requestAnimationFrame(o)}catch(t){o()}return{destroy(){r=!0,c()},reset(){if(!r){n=!1;try{window.addEventListener("scroll",i,{passive:!0})}catch(t){try{window.addEventListener("scroll",i)}catch(t){}}try{window.requestAnimationFrame(o)}catch(t){o()}}}}})(n=>{U(()=>t.track("Scrolled",{percent:n}))}),y.push(()=>null==b?void 0:b.destroy())),c.spa){const n=[],e=function(){if("undefined"==typeof window||"undefined"==typeof history)return()=>{};let e=_();function r(){try{const r=_();if(r===e)return;e=r,(e=>{const r=setTimeout(()=>{const e=n.indexOf(r);-1!==e&&n.splice(e,1),U(()=>t.page())},0);n.push(r),null==b||b.reset(),p(e)})(r)}catch(t){}}const o=history.pushState,i=history.replaceState,c=!0===o[I],u=!0===i[I];if(!c){function a(...t){o.apply(this,t),r()}a[I]=!0,history.pushState=a}if(!u){function f(...t){i.apply(this,t),r()}f[I]=!0,history.replaceState=f}const l=()=>r(),s=()=>r();try{window.addEventListener("popstate",l),window.addEventListener("hashchange",s)}catch(d){}return()=>{try{window.removeEventListener("popstate",l),window.removeEventListener("hashchange",s)}catch(t){}try{!c&&history.pushState[I]&&(history.pushState=o),!u&&history.replaceState[I]&&(history.replaceState=i)}catch(t){}}}();y.push(()=>{for(let t=0;t<n.length;t++)clearTimeout(n[t]);n.length=0,e()})}return p(),()=>{for(;y.length>0;){const t=y.pop();try{null==t||t()}catch(t){}}v=null}}(m,t)}if(a){try{a()}catch(t){}a=null}if(i.remoteConfig.enabled&&t){const n=t=>{if(a){try{a()}catch(t){}a=null}t&&t.rules&&t.rules.length>0&&(a=w(m,t))},e=(t=>{const n=G(t);return n?Q(n.envelope):null})(t);e&&n(e),function(t){return C(this,void 0,void 0,function*(){if(!t.projectId)return{status:"error"};const n=G(t.projectId);if(n&&Date.now()-n.fetchedAt<t.ttlMs)return{status:"unchanged"};const e=yield function(t){return C(this,void 0,void 0,function*(){var n;if("function"!=typeof fetch)return null;const e=t.endpoint+t.path+"?projectId="+encodeURIComponent(t.projectId),r="undefined"!=typeof AbortController?new AbortController:null,o=r?setTimeout(()=>r.abort(),t.timeoutMs):null;try{const o={};t.etag&&(o["If-None-Match"]=t.etag);const i=yield fetch(e,{method:"GET",headers:o,credentials:"omit",mode:"cors",signal:r?r.signal:void 0});if(304===i.status)return{envelope:null,etag:null!==(n=t.etag)&&void 0!==n?n:"",notModified:!0};if(!i.ok)return null;const c=i.headers&&"function"==typeof i.headers.get?i.headers.get("ETag"):null;return{envelope:yield i.json(),etag:null!=c?c:"",notModified:!1}}catch(t){return null}finally{o&&clearTimeout(o)}})}({endpoint:t.endpoint,path:t.path,projectId:t.projectId,timeoutMs:t.timeoutMs,etag:null==n?void 0:n.etag});return e?e.notModified?(n&&F(t.projectId,n.etag,n.envelope),{status:"unchanged"}):e.envelope?(F(t.projectId,e.etag,e.envelope),{status:"updated",buttonTracking:Q(e.envelope)}):{status:"error"}:{status:"error"}})}({endpoint:i.endpoint,path:i.remoteConfig.path,projectId:t,timeoutMs:i.remoteConfig.timeoutMs,ttlMs:i.remoteConfig.ttlMs}).then(t=>{"updated"===t.status&&n(t.buttonTracking)}).catch(()=>{})}}catch(t){}},pageview:v,page:p,screen(t,n){try{const e=h();if(!e)return y("screen");const r=((t,n,e)=>{const r=at("screen",e);return t&&(r.name=t),r.properties=null!=n?n:{},r})(t,n,e);d().enqueue(r)}catch(t){}},track:b,identify(t,n){try{if("string"!=typeof t||0===t.length)return;((t,n,e={})=>{var r,o;if(t&&(L(gt,t,{domain:e.cookieDomain,maxAgeDays:null!==(r=e.cookieMaxAgeDays)&&void 0!==r?r:730,sameSite:"Lax"}),z(gt,t),null!=n)){const t=null!==(o=(()=>{const t=q(wt);if(!t)return null;try{const n=JSON.parse(t);return n&&"object"==typeof n&&!Array.isArray(n)?n:null}catch(t){return null}})())&&void 0!==o?o:{},e=Object.assign(Object.assign({},t),n);try{z(wt,JSON.stringify(e))}catch(t){}}})(t,n,{cookieDomain:i.cookieDomain,cookieMaxAgeDays:i.cookieMaxAgeDays});const e=h();if(!e)return y("identify");const r=((t,n,e)=>{var r;const o=at("identify",e);return t&&(o.userId=t),o.traits=null!==(r=n)&&void 0!==r?r:{},o})(t,n,e);d().enqueue(r)}catch(t){}},alias(t,n){try{if("string"!=typeof t||0===t.length)return;const e=h();if(!e)return y("alias");const r=((t,n,e)=>{const r=at("alias",e);return t&&(r.userId=t),r.previousId=null!=n?n:e.anonymousId,r})(t,n,e);d().enqueue(r)}catch(t){}},group(t,n){try{if("string"!=typeof t||0===t.length)return;const e=h();if(!e)return y("group");const r=((t,n,e)=>{const r=at("group",e);return r.groupId=t,r.traits=null!=n?n:{},r})(t,n,e);d().enqueue(r)}catch(t){}},reset(){try{((t={})=>{((t,n={})=>{var e;if(!N)return!1;try{let r=`${encodeURIComponent(t)}=`;return r+=`; path=${null!==(e=n.path)&&void 0!==e?e:"/"}`,n.domain&&(r+=`; domain=${n.domain}`),r+="; max-age=0",r+="; expires=Thu, 01 Jan 1970 00:00:00 GMT",document.cookie=r,null===$(t)}catch(t){return!1}})(gt,{domain:t.cookieDomain}),E(gt),E(wt)})({cookieDomain:i.cookieDomain}),((t={})=>{ut(et(),t)})({cookieDomain:i.cookieDomain,cookieMaxAgeDays:i.cookieMaxAgeDays}),((t={})=>{yt({id:et(),lastActivity:Date.now()},t)})({cookieDomain:i.cookieDomain,timeoutMinutes:i.sessionTimeoutMinutes})}catch(t){}},flush(){try{u&&u.flush()}catch(t){}},consent(t){try{c=Object.assign(Object.assign({},c),t)}catch(t){}},set(t){try{i=f(t),t.consent&&(c=Object.assign(Object.assign({},c),t.consent)),u&&u.setConfig({endpoint:i.endpoint,batchPath:i.batchPath,singlePath:i.singlePath,useBatch:i.useBatch,contentType:i.contentType,flushAt:i.flushAt,flushInterval:i.flushInterval,debug:i.debug})}catch(t){}},destroy(){if(s){try{s()}catch(t){}s=null}if(a){try{a()}catch(t){}a=null}u&&u.destroy(),u=null,l=!1,t=null,i=Object.assign({},jt),c=Object.assign({},kt)}}}();function Dt(t){return It({projectId:Mt.projectId,endpoint:Mt.endpoint,zaloQrLoginEnabled:Mt.isZaloQrLoginEnabled(),consentGranted:Mt.consentGranted,identify:Mt.identify,alias:Mt.alias,getUserId:xt},t)}"undefined"!=typeof window&&(t=>{if("undefined"==typeof window)return()=>{};const n=window.cnvQ;if(n&&n.__loaded)return()=>{};const e=window.cnvQ=null!=n?n:[],r=e.splice(0,e.length);e.push.bind(e),e.push=(...n)=>{for(const e of n)Ot(t,e);return e.length},e.__loaded=!0;for(const n of r)Ot(t,n)})(Mt);const Ut=Object.assign(Mt,{version:_t,name:Pt,schemaVersion:lt,loginWithZalo:Dt});t.NAME=Pt,t.SCHEMA_VERSION=lt,t.VERSION=_t,t.ZaloQrLoginError=Tt,t.default=Ut,t.loginWithZalo=Dt,Object.defineProperty(t,"t",{value:!0})},"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).cnvTrack={});
@@ -1,797 +0,0 @@
1
- /**
2
- * ============================================================================
3
- * cnv-track.js — Data Schema (Segment Spec compatible)
4
- * ============================================================================
5
- *
6
- * Wire-format contract with the CNV Tracking Gateway. Mirrors the Segment
7
- * Spec common envelope (camelCase keys) so payloads decode 1:1 into the
8
- * server-side `SegmentMessage` / `SegmentBatchRequest` DTOs.
9
- *
10
- * Endpoints (relative to `SDKOptions.endpoint`, default `https://tracking.cnvcdp.com/js/v1`):
11
- *
12
- * POST /segment/batch ← N messages per request (default flush)
13
- * POST /segment/{type} ← single-message mode (debug / unbatched)
14
- * where {type} ∈ track | identify | page | screen | group | alias
15
- *
16
- * Where `projectId` lives:
17
- * - URL query param `?projectId=…` (routing / auth at the edge)
18
- * - `BatchRequest.context.projectId` (so backend can read off the body too)
19
- * - `SegmentMessage.context.projectId` (per-message, in case messages get
20
- * forwarded individually downstream)
21
- *
22
- * Compatibility policy:
23
- * - Additive changes (new optional fields) → minor `SCHEMA_VERSION` bump.
24
- * - Renames / removals / type changes → bump major.
25
- * ============================================================================
26
- */
27
- /** Wire-format schema version. Stamped into `context.schemaVersion` per message. */
28
- declare const SCHEMA_VERSION: "1.0";
29
- /** ISO-8601 timestamp string with millisecond precision and timezone offset. */
30
- type ISOTimestamp = string;
31
- /** RFC-4122 v4 UUID string. */
32
- type UUID = string;
33
- /**
34
- * Request `Content-Type`. `text/plain` is CORS-safelisted, so the browser
35
- * skips the OPTIONS preflight (and `sendBeacon` fires cleanly during unload);
36
- * `application/json` is stricter on the wire but triggers a preflight. The
37
- * JSON body itself is identical either way — only the header differs. See
38
- * Sub-task 4.3.
39
- */
40
- type ContentType = 'text/plain' | 'application/json';
41
- /** JSON-serializable primitive. */
42
- type JSONPrimitive = string | number | boolean | null;
43
- /** Any JSON-serializable value. */
44
- type JSONValue = JSONPrimitive | JSONValue[] | {
45
- [key: string]: JSONValue;
46
- };
47
- /**
48
- * The six message types the gateway accepts. Mirrors the regex in
49
- * `@PostMapping("segment/{type:track|identify|page|screen|group|alias}")`.
50
- */
51
- type MessageType = 'track' | 'identify' | 'page' | 'screen' | 'group' | 'alias';
52
- interface ContextPage {
53
- /** Full URL including query string and fragment. */
54
- url: string;
55
- /** Pathname only (e.g., `/products/42`). */
56
- path: string;
57
- /** Query string including the leading `?`. Empty string if none. */
58
- search: string;
59
- /** Hash fragment including the leading `#`. Empty string if none. */
60
- hash: string;
61
- /** `document.title` at the time the event was created. */
62
- title: string;
63
- /** `document.referrer` — may be empty for direct visits. */
64
- referrer: string;
65
- }
66
- interface ContextScreen {
67
- width: number;
68
- height: number;
69
- /** `window.devicePixelRatio` — useful for high-DPI segmentation. */
70
- density: number;
71
- }
72
- /**
73
- * Marketing attribution block. Field names follow the Segment Spec:
74
- * utm_campaign → name utm_source → source utm_medium → medium
75
- * utm_term → term utm_content → content
76
- *
77
- * `id` and `clickIds` are CNV extensions (no Segment equivalent) — Spring
78
- * Jackson will route them through `SegmentMessage.extra` if a strict mapping
79
- * exists, or via `Map<String, Object>` if `context` stays loosely typed.
80
- */
81
- interface ContextCampaign {
82
- /** `utm_campaign` — Segment maps to `campaign.name`. */
83
- name?: string;
84
- /** `utm_source` */
85
- source?: string;
86
- /** `utm_medium` */
87
- medium?: string;
88
- /** `utm_term` */
89
- term?: string;
90
- /** `utm_content` */
91
- content?: string;
92
- /** `utm_id` — CNV extension. */
93
- id?: string;
94
- /**
95
- * Platform click IDs (gclid, fbclid, ttclid, msclkid, dclid, ...).
96
- * CNV extension — collected verbatim from the query string.
97
- */
98
- clickIds?: Record<string, string>;
99
- }
100
- interface ContextLibrary {
101
- /** Always `@cnv/track`. */
102
- name: string;
103
- /** Semver string. Stamped at build time. */
104
- version: string;
105
- }
106
- interface ContextConsent {
107
- analytics: boolean;
108
- marketing: boolean;
109
- }
110
- interface PayloadContext {
111
- page?: ContextPage;
112
- screen?: ContextScreen;
113
- /** `navigator.language` (e.g., `vi-VN`). */
114
- locale?: string;
115
- /** IANA timezone (e.g., `Asia/Ho_Chi_Minh`). */
116
- timezone?: string;
117
- /** Verbatim `navigator.userAgent`. Gateway is expected to parse + drop. */
118
- userAgent?: string;
119
- library?: ContextLibrary;
120
- campaign?: ContextCampaign;
121
- /**
122
- * Pre-consent flag. Gateway may downgrade storage or skip forwarding to
123
- * marketing destinations when `marketing === false`.
124
- */
125
- consent?: ContextConsent;
126
- /**
127
- * CNV extension — projectId is duplicated here so backend code that
128
- * forwards individual messages still has access to the source project
129
- * without having to thread the batch-level context through.
130
- */
131
- projectId?: string;
132
- /** SDK wire-format version. Echoed for forward-compat triage. */
133
- schemaVersion?: string;
134
- }
135
- /**
136
- * One event in the wire format.
137
- *
138
- * Field name and types deliberately mirror `com.cnv.tracking.dto.SegmentMessage`
139
- * so Jackson decodes the payload into typed fields rather than the `extra`
140
- * map. Any field NOT listed here will land in `extra` on the server side.
141
- *
142
- * type — Discriminator. Required.
143
- * messageId — UUID v4 per event. Server uses for idempotent dedupe.
144
- * anonymousId — Device-level id from cookie + localStorage.
145
- * userId — Authenticated user id (only after `identify()`).
146
- * sessionId — Rotates after 30' inactivity. Java accepts `session_id` alias.
147
- * timestamp — When the event was created on the client.
148
- * originalTimestamp — Stamped once on the client; never overridden during
149
- * offline retries. Equal to `timestamp` on first send.
150
- * sentAt — Stamped just before the request leaves the browser.
151
- *
152
- * event — Custom event name. ONLY for type=track.
153
- * name — Page / screen name. For type=page or type=screen.
154
- * category — Optional grouping. For type=page or type=screen.
155
- * properties — For track / page / screen.
156
- * traits — For identify / group.
157
- *
158
- * groupId — Required for type=group.
159
- * previousId — Required for type=alias (the *old* id being aliased away).
160
- *
161
- * context — Auto-collected environment (see {@link PayloadContext}).
162
- * integrations— Per-destination on/off toggles (Segment convention).
163
- */
164
- interface SegmentMessage {
165
- type: MessageType;
166
- messageId: UUID;
167
- anonymousId: UUID;
168
- userId?: string;
169
- sessionId?: string;
170
- timestamp: ISOTimestamp;
171
- originalTimestamp: ISOTimestamp;
172
- sentAt?: ISOTimestamp;
173
- event?: string;
174
- name?: string;
175
- category?: string;
176
- properties?: Record<string, JSONValue>;
177
- traits?: Record<string, JSONValue>;
178
- context?: PayloadContext;
179
- groupId?: string;
180
- previousId?: string;
181
- integrations?: Record<string, JSONValue>;
182
- }
183
- /**
184
- * Wrapper sent to `POST /segment/batch`. Shape matches
185
- * `com.cnv.tracking.dto.SegmentBatchRequest`:
186
- *
187
- * batch — N SegmentMessage records.
188
- * context — Batch-level context. We use it to hoist `projectId` once
189
- * instead of repeating per message. (Per-message context
190
- * still carries page / screen / campaign as those vary
191
- * between events in the same batch — SPA navigation, etc.)
192
- * integrations — Batch-level destination toggles.
193
- */
194
- interface SegmentBatchRequest {
195
- batch: SegmentMessage[];
196
- context?: Record<string, JSONValue>;
197
- integrations?: Record<string, JSONValue>;
198
- sentAt?: ISOTimestamp;
199
- }
200
- /** Argument shape for `identify(userId, traits)`. */
201
- interface UserTraits {
202
- email?: string;
203
- phone?: string;
204
- name?: string;
205
- firstName?: string;
206
- lastName?: string;
207
- createdAt?: ISOTimestamp;
208
- [key: string]: JSONValue | undefined;
209
- }
210
- interface SDKOptions {
211
- /** Tracking Gateway base URL. Default: `https://tracking.cnvcdp.com/js/v1`. */
212
- endpoint?: string;
213
- /** Path appended for batch flush. Default: `/segment/batch`. */
214
- batchPath?: string;
215
- /** Per-type single-message path template. `{type}` is interpolated. */
216
- singlePath?: string;
217
- /** Use batch endpoint (true, default) or one request per event. */
218
- useBatch?: boolean;
219
- /**
220
- * Request `Content-Type`. Default `text/plain` — CORS-safelisted, so no
221
- * OPTIONS preflight. Switch to `application/json` only if the gateway
222
- * rejects text bodies (then it must allow the preflight). See Sub-task 4.3.
223
- */
224
- contentType?: ContentType;
225
- /** Verbose console output. */
226
- debug?: boolean;
227
- /** Disable marketing-related identifiers and click-id capture. */
228
- allowAdTracking?: boolean;
229
- /** Cookie domain (e.g., `.cnv.vn` for cross-subdomain stitching). */
230
- cookieDomain?: string;
231
- /** Cookie lifetime in days. Default 730 (≈ 2 years, ITP-safe upper bound). */
232
- cookieMaxAgeDays?: number;
233
- /** Session inactivity timeout in minutes. Default 30. */
234
- sessionTimeoutMinutes?: number;
235
- /** Buffered events before forced flush. Default 20. */
236
- flushAt?: number;
237
- /** Max ms between flushes. Default 5000. */
238
- flushInterval?: number;
239
- /** Fire a `pageview` automatically on `init()`. Default true. */
240
- autoPageview?: boolean;
241
- /**
242
- * Enhanced Measurement — opt-in automatic instrumentation. Mirrors the
243
- * features GA4's gtag enables by default. Pass `true` to enable every
244
- * feature with sensible defaults, `false` to disable, or a granular object
245
- * to flip individual features. See {@link AutotrackOptions}.
246
- *
247
- * Default: `false` (off, for backward compatibility).
248
- */
249
- autotrack?: boolean | AutotrackOptions;
250
- /** Initial consent state. Default `{ analytics: true, marketing: true }`. */
251
- consent?: Partial<ContextConsent>;
252
- /** Per-call integrations override. */
253
- integrations?: Record<string, JSONValue>;
254
- /**
255
- * Remote config — tự nạp button-tracking rules từ Tracking Gateway
256
- * (`GET {endpoint}{path}?projectId=`) lúc `init`. Rule do dashboard CDP quản
257
- * lý (single source of truth); SDK chỉ đọc + cache (localStorage + ETag) và
258
- * fail-open. **Mặc định on** — SDK tự nạp rules mà không cần khai báo. Pass
259
- * `false` để tắt, hoặc object để tinh chỉnh. Xem {@link RemoteConfigOptions}.
260
- */
261
- remoteConfig?: boolean | RemoteConfigOptions;
262
- }
263
- /**
264
- * Tùy chọn cho remote-config fetch. Nguồn rule là dashboard CDP — SDK chỉ tải
265
- * bản đã publish qua `GET {endpoint}{path}?projectId=` rồi cache lại.
266
- */
267
- interface RemoteConfigOptions {
268
- /** Bật/tắt. Mặc định `true` khi truyền object. */
269
- enabled?: boolean;
270
- /** Path nối sau `endpoint` để lấy config. Mặc định `/config`. */
271
- path?: string;
272
- /** Timeout cho request fetch config (ms). Mặc định 4000. */
273
- timeoutMs?: number;
274
- /**
275
- * Cửa sổ "còn tươi" của cache localStorage (ms): trong khoảng này SDK dùng
276
- * thẳng cache, không gọi mạng. Mặc định 300000 (khớp `max-age=300` server).
277
- */
278
- ttlMs?: number;
279
- }
280
- /**
281
- * Granular toggles for the built-in autotrack instrumentation. Every feature
282
- * defaults to `true` when `autotrack: true`, or can be individually flipped
283
- * when the user passes an object.
284
- *
285
- * Event names follow Segment Spec conventions where one exists, with CNV
286
- * extensions for the rest:
287
- * - SPA pageview → emits `type:"page"` (same as manual `page()`)
288
- * - Outbound link click → `track('Clicked', { url, … })`
289
- * - 90% scroll depth → `track('Scrolled', { percent: 90 })`
290
- * - File download click → `track('File Downloaded', { url, extension, … })`
291
- * - Site search (?q= …) → `track('Site Searched', { query })`
292
- */
293
- interface AutotrackOptions {
294
- /**
295
- * Monkey-patch `history.pushState` / `history.replaceState` and listen for
296
- * `popstate` + `hashchange` so SPA route changes (React Router, Vue Router,
297
- * Next.js App Router, …) fire a `page()` automatically. Default `true`.
298
- */
299
- spa?: boolean;
300
- /**
301
- * Document-level click delegation. Fires `track('Clicked')`
302
- * when the user clicks an `<a>` whose host differs from `location.host`.
303
- * Default `true`.
304
- */
305
- outboundClicks?: boolean;
306
- /**
307
- * Passive scroll listener that fires `track('Scrolled', { percent: 90 })`
308
- * exactly once per page when the user reaches ≥ 90% of the document height.
309
- * Re-armed on SPA route change. Default `true`.
310
- */
311
- scroll?: boolean;
312
- /**
313
- * Same click delegation pipeline as `outboundClicks`. Fires
314
- * `track('File Downloaded')` when an `<a href>` points at a recognized
315
- * file extension (pdf, doc/docx, xls/xlsx, ppt/pptx, zip, rar, 7z, csv,
316
- * txt, mp3, mp4, mov, wav, dmg, exe, pkg, gz). Default `true`.
317
- */
318
- downloads?: boolean;
319
- /**
320
- * Inspect the URL query string for common search parameter names
321
- * (`q`, `s`, `query`, `search`, `keyword`) and fire
322
- * `track('Site Searched', { query })` whenever a non-empty value is found
323
- * at pageview time. Default `true`.
324
- */
325
- siteSearch?: boolean;
326
- /**
327
- * Additional file extensions to treat as downloads (merged with defaults).
328
- * Lower-case, no leading dot.
329
- */
330
- downloadExtensions?: ReadonlyArray<string>;
331
- /**
332
- * Override the list of query parameter names checked by `siteSearch`.
333
- * Order matters — first non-empty match wins.
334
- */
335
- searchParams?: ReadonlyArray<string>;
336
- /**
337
- * Configurable button / element click tracking. Unlike `outboundClicks`
338
- * (which auto-fires on every outbound anchor), this fires ONLY for elements
339
- * matching a user-defined rule — the mechanism for tracking specific buttons
340
- * (e.g. "Mua", "Đặt hàng") without flooding analytics with noise.
341
- *
342
- * In Phase 1 the rules are supplied inline here. In a later phase the same
343
- * {@link ClickRule} shape is fetched from remote config so non-technical
344
- * users can manage rules from the dashboard without redeploying the site.
345
- *
346
- * Default: undefined (no button tracking).
347
- */
348
- buttonTracking?: ButtonTrackingOptions;
349
- }
350
- /**
351
- * Top-level button-tracking config. A flat list of rules plus optional global
352
- * throttle defaults that individual rules can override.
353
- */
354
- interface ButtonTrackingOptions {
355
- /** Rules evaluated (ascending `priority`) against every click. */
356
- rules: ClickRule[];
357
- /** Throttle defaults applied to rules that don't set their own. */
358
- globalThrottle?: ThrottleSpec;
359
- }
360
- /**
361
- * One button-tracking rule. A click matches the rule when EVERY field present
362
- * in `match` is satisfied by the same element (logical AND). The first
363
- * matching rule (lowest `priority`) wins and fires the fixed `Clicked` event;
364
- * the rule's `event.name` (if set) is attached as the `event_name` property.
365
- */
366
- interface ClickRule {
367
- /** Stable id (ULID from backend). Stamped onto the event as `rule_id`. */
368
- id: string;
369
- /** Human label, e.g. "Nút Mua hàng". Optional; stamped as `rule_name`. */
370
- name?: string;
371
- /** Default `true`. Set `false` to keep the rule but stop it firing. */
372
- enabled?: boolean;
373
- /** Lower runs first. Default `0`. */
374
- priority?: number;
375
- /** Conditions that select which element(s) this rule applies to. */
376
- match: ClickMatch;
377
- /** What event to emit when the rule matches. */
378
- event: ClickEventSpec;
379
- /** Properties to auto-collect from the matched element. */
380
- capture?: CaptureSpec;
381
- /** Per-rule noise controls (override `globalThrottle`). */
382
- throttle?: ThrottleSpec;
383
- /** Restrict the rule to certain pages. */
384
- urlScope?: UrlMatch;
385
- }
386
- /**
387
- * Element selection criteria. All present fields are AND-ed and evaluated
388
- * against the SAME element (the nearest matching ancestor of the click target).
389
- */
390
- interface ClickMatch {
391
- /**
392
- * Element type filter. Special values: `'button'` (button / input[submit|
393
- * button|reset] / [role=button]), `'link'` (anchor), `'any'`. Any other
394
- * string is treated as a CSS selector. When omitted, defaults to the
395
- * actionable set (button-like + link) unless another attribute/selector
396
- * criterion is present, in which case it defaults to `'any'`.
397
- */
398
- element?: 'button' | 'link' | 'any' | (string & {});
399
- /** Match the element's visible text. */
400
- text?: TextMatch;
401
- /** Match `element.id` exactly. */
402
- id?: string;
403
- /** Element must carry ALL of these CSS classes. */
404
- classes?: string[];
405
- /** Match a `data-*` attribute (presence, or exact value if `value` given). */
406
- dataAttr?: DataAttrMatch;
407
- /** Free-form CSS selector; matched via `element.matches(selector)`. */
408
- selector?: string;
409
- /** Match the URL the button/link navigates to (anchor href, formaction, form action, or data-href). */
410
- destinationUrl?: DestinationMatch;
411
- }
412
- interface TextMatch {
413
- mode: 'contains' | 'exact' | 'startsWith' | 'regex';
414
- value: string;
415
- /** Default `true`. Ignored for `regex` except to add the `i` flag. */
416
- caseInsensitive?: boolean;
417
- }
418
- interface DataAttrMatch {
419
- /** Full attribute name, e.g. `data-track`. */
420
- name: string;
421
- /** If omitted, presence is enough; otherwise exact value match. */
422
- value?: string;
423
- }
424
- interface DestinationMatch {
425
- mode: 'contains' | 'exact' | 'startsWith' | 'regex' | 'domain';
426
- value: string;
427
- }
428
- interface UrlMatch {
429
- mode: 'glob' | 'regex' | 'startsWith';
430
- /** Compared against `location.pathname + location.search`. */
431
- value: string;
432
- }
433
- /** The event emitted when a rule matches — keeps captured data clean & named. */
434
- interface ClickEventSpec {
435
- /**
436
- * Optional user-supplied label, e.g. "Add to Cart". The event itself is
437
- * always emitted as `Clicked`; this name is attached as the `event_name`
438
- * property when present. Omit to fire `Clicked` with no `event_name`.
439
- */
440
- name?: string;
441
- /** Constant properties merged into every event this rule fires. */
442
- staticProps?: Record<string, string | number | boolean>;
443
- }
444
- /** Allowlist of properties to auto-collect from the matched element. */
445
- interface CaptureSpec {
446
- /** Visible text (trimmed, capped at 200 chars, PII-scrubbed). */
447
- text?: boolean;
448
- /** Resolved absolute destination URL. */
449
- href?: boolean;
450
- /** `element.id`. */
451
- elementId?: boolean;
452
- /** `element.classList` as an array. */
453
- classes?: boolean;
454
- /** Names of `data-*` attributes to copy (PII-scrubbed). */
455
- dataAttrs?: string[];
456
- /** Read a value from a descendant selector (e.g. a price near the button). */
457
- valueFrom?: {
458
- selector: string;
459
- attr?: string;
460
- as: string;
461
- };
462
- /** A short CSS path of the element (debug / attribution). */
463
- selectorPath?: boolean;
464
- /** Click coordinates `{ x, y }`. */
465
- position?: boolean;
466
- }
467
- interface ThrottleSpec {
468
- /** Ignore repeat clicks on the same element within this window. Default 500. */
469
- dedupeWindowMs?: number;
470
- /** Cap events fired per rule per pageview. Default unlimited. */
471
- maxPerPageview?: number;
472
- /** Probability 0..1 an eligible click is recorded. Default 1. */
473
- samplingRate?: number;
474
- }
475
- /**
476
- * Envelope trả về từ `GET /v1/config` (remote config). SDK parse trực tiếp; chỉ
477
- * dùng phần `buttonTracking`, các field nội bộ khác (nếu có) được bỏ qua.
478
- */
479
- interface RemoteConfigEnvelope {
480
- /** Tăng mỗi lần publish; cũng là giá trị `ETag` để cache-bust. */
481
- version: number;
482
- /** Phiên bản schema rule, ví dụ `"1.0"`. */
483
- schemaVersion?: string;
484
- /** ISO timestamp lần publish gần nhất. */
485
- updatedAt?: string;
486
- /** Cấu hình button-tracking đã publish. */
487
- buttonTracking?: {
488
- /** `false` ⇒ tắt button-tracking (SDK gỡ listener). */
489
- enabled?: boolean;
490
- /** Danh sách rule (giống schema inline {@link ClickRule}). */
491
- rules?: ClickRule[];
492
- /** Throttle mặc định cho rule không tự đặt. */
493
- globalThrottle?: ThrottleSpec;
494
- };
495
- /** Kill-switch QR-login Zalo từ dashboard. `enabled: false` ⇒ `loginWithZalo()` reject ngay. */
496
- zaloQrLogin?: {
497
- enabled?: boolean;
498
- };
499
- }
500
- /**
501
- * Lý do `loginWithZalo()` thất bại (`ZaloQrLoginError.reason`). LƯU Ý phạm vi
502
- * reject khác nhau:
503
- * - `'not-initialized' | 'disabled' | 'consent-required' | 'invalid-project-key'
504
- * | 'project-suspended' | 'network'`: reject ngay lời gọi `loginWithZalo(...)`
505
- * (trước khi có {@link ZaloQrLoginSession}) — lỗi thiết lập phiên, không có
506
- * `session`/`session.result` nào để bắt.
507
- * - `'expired' | 'denied' | 'cancelled'`: reject {@link ZaloQrLoginSession.result}
508
- * — xảy ra SAU khi đã có `session` (QR đã hiển thị), khi chờ kết quả quét.
509
- *
510
- * Bọc `try/catch` quanh CẢ hai điểm `await` (xem ví dụ ở `loginWithZalo` JSDoc)
511
- * để không bỏ sót nhóm đầu.
512
- *
513
- * `'invalid-project-key'`/`'project-suspended'` tách riêng khỏi `'network'` dựa
514
- * theo HTTP status server trả về (401/403) — đây là lỗi CẤU HÌNH (project key
515
- * gõ sai/thiếu, hoặc project bị khoá), KHÔNG PHẢI lỗi mạng/CORS thật. Trước đây
516
- * cả 2 nhóm bị gộp chung `'network'`, khiến integrator debug sai hướng.
517
- */
518
- type ZaloQrLoginErrorReason = 'not-initialized' | 'disabled' | 'consent-required' | 'invalid-project-key' | 'project-suspended' | 'network' | 'expired' | 'denied' | 'cancelled';
519
- /** Tuỳ chọn cho `loginWithZalo()`. */
520
- interface ZaloQrLoginOptions {
521
- /** Ưu tiên SSE (mặc định `true`); `false` ⇒ chỉ dùng poll ngay từ đầu. */
522
- preferSse?: boolean;
523
- /** Khoảng poll fallback (ms). Mặc định 2000. */
524
- pollIntervalMs?: number;
525
- /**
526
- * Mặc định `true` — quét thành công thì SDK **tự chọn** giữa `identify()`/`alias()`, integrator
527
- * không cần tự nghĩ về ca "site đã có tài khoản riêng":
528
- * - Chưa từng `identify()` trước đó → Zalo QR là cách đăng nhập chính → `identify(String(contactId), {...})`.
529
- * - Đã có `userId` từ trước (site tự `identify()` sau login thường của họ) → **không ghi đè** —
530
- * `alias(String(contactId), userId cũ)` để backend biết 2 ID là cùng một người, `userId`
531
- * hiện tại giữ nguyên, lịch sử tracking không bị "nhảy" giữa chừng.
532
- *
533
- * Đặt `false` để tắt hẳn cả 2 nhánh trên, tự quyết định 100% bằng `result.contactId` — xem
534
- * "autoIdentify: false" trong docs.
535
- */
536
- autoIdentify?: boolean;
537
- }
538
- /**
539
- * Kết quả khi người dùng quét QR và xác thực Zalo thành công.
540
- *
541
- * KHÔNG có `phone` — số điện thoại thật KHÔNG được trả về client (cùng lý do đã bỏ
542
- * `apiToken`/`loginToken`: PII/credential lộ ra bất kỳ script nào chạy chung trang hoặc
543
- * ai mở DevTools). `contactId` là định danh dùng để `identify()` — nếu cần số điện thoại
544
- * cho nghiệp vụ, tự tra cứu ở backend của bạn bằng `contactId` (đã xác thực thật).
545
- */
546
- interface ZaloQrLoginResult {
547
- contactId?: number;
548
- /** Họ tên đầy đủ của contact trong CDP (nếu có). */
549
- fullName?: string;
550
- /** Tên hạng thành viên hiện tại (nếu có). */
551
- level?: string;
552
- /** Điểm kinh nghiệm/tích luỹ hiện tại (nếu có). */
553
- xp?: number;
554
- }
555
- /**
556
- * Phiên QR-login đang chờ người dùng quét. SDK KHÔNG tự vẽ QR — host page tự
557
- * render từ `qrPayload` (deep-link Mini App Zalo), rồi `await session.result`
558
- * để nhận kết quả khi quét xong (hoặc bắt lỗi nếu hết hạn/bị từ chối/huỷ).
559
- */
560
- interface ZaloQrLoginSession {
561
- sessionToken: string;
562
- /** Deep-link Mini App Zalo — host tự vẽ thành mã QR. */
563
- qrPayload: string;
564
- expiresInSeconds: number;
565
- /**
566
- * Resolve khi quét xong & backend xác nhận; reject với {@link ZaloQrLoginError}
567
- * có `reason` là `'expired' | 'denied' | 'cancelled'` (xem {@link ZaloQrLoginErrorReason}
568
- * để phân biệt với lỗi thiết lập phiên, vốn reject lời gọi `loginWithZalo()` chứ
569
- * không phải field này).
570
- */
571
- result: Promise<ZaloQrLoginResult>;
572
- /** Huỷ sớm phía client (đóng SSE/dừng poll, reject `result` với `'cancelled'`). Không huỷ được phiên phía server — phiên tự hết hạn theo TTL. */
573
- cancel: () => void;
574
- /**
575
- * Tạo phiên MỚI (QR mới) — dùng khi `result` đã reject với `'expired'` (hoặc `'denied'`,
576
- * hoặc để chủ động "làm mới QR" theo yêu cầu người dùng). Tự huỷ phiên hiện tại trước khi
577
- * tạo phiên mới (an toàn gọi ngay cả khi phiên đã kết thúc — no-op phần huỷ đó); trả về
578
- * {@link ZaloQrLoginSession} MỚI hoàn toàn (không mutate session cũ) — host render lại QR
579
- * từ `qrPayload` của session mới rồi `await` `result` mới như bình thường.
580
- */
581
- retry: () => Promise<ZaloQrLoginSession>;
582
- }
583
- /**
584
- * Each entry in `window.cnvQ` is a tuple `[methodName, ...args]`.
585
- * The async snippet seeds the queue as a plain Array; once the SDK loads,
586
- * it drains the queue and replaces `.push` with a synchronous dispatcher.
587
- *
588
- * Discriminated by tuple index 0 for exhaustive type-narrowing.
589
- */
590
- type QueuedCommand = readonly ['init', string, SDKOptions?] | readonly ['pageview', string?, Record<string, JSONValue>?] | readonly ['page', string?, Record<string, JSONValue>?] | readonly ['screen', string?, Record<string, JSONValue>?] | readonly ['track', string, Record<string, JSONValue>?] | readonly ['identify', string, UserTraits?] | readonly ['alias', string, string?] | readonly ['group', string, Record<string, JSONValue>?] | readonly ['reset'] | readonly ['flush'] | readonly ['consent', Partial<ContextConsent>] | readonly ['set', Partial<SDKOptions>];
591
-
592
- /**
593
- * ============================================================================
594
- * queue — Queue Processor (Sub-task 3.5)
595
- * ============================================================================
596
- *
597
- * The async snippet seeds `window.cnvQ = []` and pushes `[methodName, ...args]`
598
- * tuples while the SDK is still loading. Once this file runs, we:
599
- *
600
- * 1. Snapshot whatever the snippet pushed (the pending FIFO backlog).
601
- * 2. Replace `cnvQ.push` with a proxy that *synchronously* dispatches.
602
- * 3. Drain the snapshot through the dispatcher in original order.
603
- * 4. Mark `cnvQ.__loaded = true` so duplicate snippet includes no-op.
604
- *
605
- * Ordering note: step 2 happens BEFORE step 3 on purpose. If a dispatched
606
- * command synchronously triggers another `cnvQ.push` (e.g., a user's init
607
- * options has an `onReady` callback that fires a `track`), the new push
608
- * also goes through the proxy and stays in FIFO order with the backlog
609
- * rather than racing the drain loop.
610
- *
611
- * Every dispatch is wrapped in try/catch (Sub-task 5.2 — silent-fail
612
- * contract). A malformed command MUST NOT crash the host page or stop
613
- * the rest of the queue from draining.
614
- * ============================================================================
615
- */
616
-
617
- /**
618
- * Surface the queue forwards inbound tuples to. Each method matches one
619
- * `QueuedCommand` discriminator. The runtime (in `index.ts`) implements this.
620
- */
621
- interface Dispatcher {
622
- init(projectId: string, options?: SDKOptions): void;
623
- pageview(name?: string, properties?: Record<string, JSONValue>): void;
624
- page(name?: string, properties?: Record<string, JSONValue>): void;
625
- screen(name?: string, properties?: Record<string, JSONValue>): void;
626
- track(event: string, properties?: Record<string, JSONValue>): void;
627
- identify(userId: string, traits?: UserTraits): void;
628
- alias(userId: string, previousId?: string): void;
629
- group(groupId: string, traits?: Record<string, JSONValue>): void;
630
- reset(): void;
631
- flush(): void;
632
- consent(state: Partial<ContextConsent>): void;
633
- set(options: Partial<SDKOptions>): void;
634
- }
635
-
636
- /**
637
- * ============================================================================
638
- * runtime — SDK state holder + public API (Sub-tasks 3.1 / 3.2 / 3.3 / 3.4)
639
- * ============================================================================
640
- *
641
- * Implements the {@link Dispatcher} surface consumed by the Queue Processor.
642
- * Module-scoped state (project id, resolved options, transport instance,
643
- * consent) lives here as a singleton. `createRuntime()` exists so tests can
644
- * spin up an isolated copy without leaking state between cases.
645
- *
646
- * Public API and what each method does:
647
- * init(projectId, options?) → set up runtime, build transport,
648
- * optionally fire an automatic pageview
649
- * pageview(name?, properties?) → emit `type:"page"`
650
- * page(name?, properties?) → emit `type:"page"` (alias of pageview)
651
- * screen(name?, properties?) → emit `type:"screen"`
652
- * track(event, properties?) → emit `type:"track"`
653
- * identify(userId, traits?) → emit `type:"identify"`, persist uid
654
- * alias(userId, previousId?) → emit `type:"alias"`
655
- * group(groupId, traits?) → emit `type:"group"`
656
- * reset() → rotate anonymousId, drop userId
657
- * flush() → force-flush the transport buffer
658
- * consent(state) → merge consent flags
659
- * set(options) → patch SDK options at runtime
660
- *
661
- * Init order matters:
662
- * 1. Cookie / LS reads happen on demand (lazy) — every event resolves
663
- * its own anonymousId + sessionId at message-build time so a re-init
664
- * with new cookieDomain takes effect on the very next event.
665
- * 2. Transport is recreated whenever endpoint / batch settings change.
666
- *
667
- * Silent-fail (Sub-task 5.2):
668
- * Every public method is wrapped in try/catch. A bug inside the SDK
669
- * MUST NEVER throw out into the host page.
670
- * ============================================================================
671
- */
672
-
673
- /** Public-facing handle that exposes the SDK methods + a few internals. */
674
- interface Runtime extends Dispatcher {
675
- readonly initialized: boolean;
676
- readonly projectId: string | null;
677
- /** Gateway base URL đang dùng — cho các module bên ngoài Dispatcher (vd `zaloQrLogin`). */
678
- readonly endpoint: string;
679
- /** Đọc nhanh (đồng bộ, từ cache remote-config) cờ bật/tắt QR-login Zalo cho project hiện tại. */
680
- isZaloQrLoginEnabled(): boolean;
681
- /** `true` khi cả `analytics` và `marketing` đều được đồng ý — ngưỡng `loginWithZalo()` yêu cầu vì thu thập SĐT. */
682
- readonly consentGranted: boolean;
683
- /** Tear down timers + listeners. Test-only in production. */
684
- destroy(): void;
685
- }
686
-
687
- /**
688
- * ============================================================================
689
- * zaloQrLogin — đăng nhập bằng Zalo qua QR cho website nhúng SDK
690
- * ============================================================================
691
- *
692
- * `loginWithZalo()` là API ĐẦU TIÊN của SDK không theo hợp đồng "never throw,
693
- * fire-and-forget" của các method khác (track/identify/...) — nó trả Promise
694
- * thật, và có THỂ REJECT Ở 2 ĐIỂM khác nhau (xem `ZaloQrLoginErrorReason` ở
695
- * types.ts để biết chi tiết từng reason):
696
- * 1. Lời gọi `loginWithZalo()` chính nó — lỗi thiết lập phiên (chưa init,
697
- * dashboard tắt, thiếu consent, lỗi mạng khi tạo phiên).
698
- * 2. `session.result` — lỗi xảy ra SAU khi đã có phiên/đã hiển thị QR
699
- * (hết hạn, bị từ chối, bị huỷ).
700
- * Consumer cần bọc try/catch quanh CẢ HAI điểm await. Vì cần tương tác 2
701
- * chiều thực sự (đăng ký phiên → chờ QR được quét), hàm này KHÔNG đi qua
702
- * queue protocol `window.cnvQ` — chỉ dùng được qua ES-module import.
703
- *
704
- * SDK không tự vẽ QR: trả `qrPayload` (deep-link Mini App) để host page tự
705
- * render `<img>`/canvas, đúng vai trò "tracker" chứ không phải "auth widget"
706
- * (xem cách `demo/index.html` tự vẽ modal login cho `identify()`).
707
- *
708
- * Kênh nhận kết quả: SSE (`GET {endpoint}/zalo-qr/stream`) làm chính, tự
709
- * fallback sang poll (`GET {endpoint}/zalo-qr/status`) nếu `EventSource`
710
- * không tồn tại hoặc báo lỗi kéo dài — cùng triết lý "luôn có phương án dự
711
- * phòng" mà `transport.ts` áp dụng (sendBeacon → fetch).
712
- *
713
- * Làm mới QR hết hạn: `session.retry()` — tự huỷ phiên hiện tại (an toàn dù đã
714
- * hết hạn/bị từ chối/thành công từ trước) rồi tạo phiên MỚI với cùng host/options
715
- * ban đầu, trả về `ZaloQrLoginSession` mới để host render lại QR + await `result`
716
- * mới. Không cần tự lưu lại `host`/`opts` hay gọi lại `loginWithZalo()` thủ công.
717
- * ============================================================================
718
- */
719
-
720
- /** Lỗi nghiệp vụ của `loginWithZalo()` — xem {@link ZaloQrLoginErrorReason} cho phạm vi reject của từng reason. */
721
- declare class ZaloQrLoginError extends Error {
722
- readonly reason: ZaloQrLoginErrorReason;
723
- constructor(reason: ZaloQrLoginErrorReason);
724
- }
725
-
726
- /**
727
- * ============================================================================
728
- * cnv-track.js — public entry point
729
- * ============================================================================
730
- *
731
- * Wires the runtime (`./core/runtime.ts`) into the Queue Processor
732
- * (`./core/queue.ts`) and exposes the public API surface.
733
- *
734
- * Two consumer paths:
735
- *
736
- * 1. Script-tag (IIFE) via snippet:
737
- * Snippet seeds `window.cnvQ`, this module auto-installs the Queue
738
- * Processor on import, drains the backlog, and starts dispatching.
739
- *
740
- * 2. ES module:
741
- * `import cnvTrack from '@cnv/track'`
742
- * `cnvTrack.init('PRJ_X')`
743
- * Side-effectful auto-install still runs (a no-op if `window.cnvQ`
744
- * is empty); consumers can drive the SDK directly via the default
745
- * export or by pushing tuples through `window.cnvQ`.
746
- * ============================================================================
747
- */
748
-
749
- /** Library version. Replaced at build time by @rollup/plugin-replace. */
750
- declare const VERSION: string;
751
- /** Library name. Replaced at build time by @rollup/plugin-replace. */
752
- declare const NAME: string;
753
-
754
- /**
755
- * Đăng nhập bằng Zalo qua QR — API duy nhất của SDK trả Promise thật thay vì
756
- * silent-fail (xem `core/zaloQrLogin.ts`). KHÔNG đi qua queue protocol
757
- * `window.cnvQ` — chỉ dùng được qua ES-module import. Có THỂ REJECT Ở 2 ĐIỂM
758
- * khác nhau (xem {@link ZaloQrLoginErrorReason}) — bọc try/catch quanh cả hai
759
- * `await`, và gọi `session.cancel()` khi host đóng UI QR sớm (đóng SSE/dừng poll):
760
- *
761
- * ```ts
762
- * import { loginWithZalo, ZaloQrLoginError } from '@cnv-vn/track';
763
- *
764
- * let session;
765
- * try {
766
- * session = await loginWithZalo(); // có thể reject: not-initialized/disabled/consent-required/network
767
- * renderQr(session.qrPayload);
768
- * } catch (err) {
769
- * if (err instanceof ZaloQrLoginError) showError(err.reason);
770
- * return;
771
- * }
772
- *
773
- * // modal đóng sớm (user bấm huỷ): session.cancel();
774
- *
775
- * try {
776
- * const { contactId, fullName } = await session.result; // có thể reject: expired/denied/cancelled
777
- * onLoggedIn(contactId, fullName);
778
- * } catch (err) {
779
- * if (err instanceof ZaloQrLoginError) showError(err.reason);
780
- * }
781
- * ```
782
- */
783
- declare function loginWithZalo(opts?: ZaloQrLoginOptions): Promise<ZaloQrLoginSession>;
784
- /**
785
- * Public SDK handle. Methods correspond 1:1 with `QueuedCommand` verbs so
786
- * `window.cnvQ.push(['track', 'X'])` and `cnvTrack.track('X')` are interchangeable.
787
- * `loginWithZalo` is attached for ergonomics but is NOT part of `QueuedCommand`.
788
- */
789
- declare const cnvTrack: Runtime & {
790
- version: string;
791
- name: string;
792
- schemaVersion: "1.0";
793
- loginWithZalo: typeof loginWithZalo;
794
- };
795
-
796
- export { NAME, SCHEMA_VERSION, VERSION, ZaloQrLoginError, cnvTrack as default, loginWithZalo };
797
- export type { AutotrackOptions, ButtonTrackingOptions, CaptureSpec, ClickEventSpec, ClickMatch, ClickRule, ContextCampaign, ContextConsent, ContextLibrary, ContextPage, ContextScreen, DataAttrMatch, DestinationMatch, JSONValue, MessageType, PayloadContext, QueuedCommand, RemoteConfigEnvelope, RemoteConfigOptions, SDKOptions, SegmentBatchRequest, SegmentMessage, TextMatch, ThrottleSpec, UrlMatch, UserTraits, ZaloQrLoginErrorReason, ZaloQrLoginOptions, ZaloQrLoginResult, ZaloQrLoginSession };