@global-savings-group/caa-engine
Advanced tools
Comparing version 4.0.5 to 4.0.7
import { type UnifiedConfig } from '../../content'; | ||
import { type Code, type TestedCode } from '../code'; | ||
export declare function applyCode(tabId: number, code: Code, config: UnifiedConfig): Promise<TestedCode>; | ||
export declare function applyCode(tabId: number, code: Code, config: UnifiedConfig, timeout?: number): Promise<TestedCode>; |
@@ -1,1 +0,1 @@ | ||
(()=>{"use strict";var e={d:(t,n)=>{for(var o in n)e.o(n,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:n[o]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{AmountType:()=>i,BackgroundToClientMessageType:()=>G,ClientToBackgroundMessageType:()=>j,TestedCodeType:()=>q,getElements:()=>y,getGeneratedSelector:()=>v,getMainDomain:()=>k,setupBackgroundListeners:()=>te,setupContentListeners:()=>H});let n=()=>{};function o(e){n=e}const r={error:(e,t)=>n({level:"ERROR",message:e,stack:t instanceof Error&&t.stack||(new Error).stack||""}),info:e=>n({details:JSON.stringify(e),level:"INFO"}),perf:(e,t)=>n({label:e,level:"PERF",meta:t})};var i;function a(e){try{const[,t=""]=e.split('"');return Object(JSON.parse(decodeURI(t)))}catch{return{}}}function l(e){return a(e)}!function(e){e.Dollar="$",e.Euro="€",e.Percent="%",e.Pound="£",e.Real="R$",e.Zloty="zł"}(i||(i={}));const u=/[0-9.,]+/g;function s(e){return e?e.normalize("NFC").replaceAll(u,""):null}const c="data-caa-text";function d({innerText:e,tagName:t}){return function(e){try{return encodeURI(JSON.stringify(e))}catch(e){return r.error("Cannot encode a custom cssSelector: ",e),""}}({innerText:e,tagName:t})}function f(e){const{tagName:t,innerText:n}=a(e);return e.includes(c)&&"string"==typeof t&&"string"==typeof n}function p(e){return f(e)}function m(e){const t=Array.from(document.querySelectorAll(e));return f(e)?t.length>0?t.filter((n=e,function(e){const{tagName:t,innerText:o}=l(n);return e.tagName===t&&s(e.innerText)===s(o)})):function(e){const{tagName:t,innerText:n}=l(e);return Array.from(document.getElementsByTagName(t)).filter((e=>e instanceof HTMLElement)).filter((e=>s(e.innerText)===s(n))).map((e=>(e.setAttribute(c,d(e)),e)))}(e):[];var n}function h(e){try{if(p(e)){const[t=null]=m(e);return t}return document.querySelector(e)}catch(t){return r.error(`Cannot find the element in the DOM with the selector="${e}":`,t),null}}function y(e){try{return p(e)?m(e):Array.from(document.querySelectorAll(e))}catch(t){return r.error(`Cannot find elements in the DOM with the selector="${e}":`,t),[]}}function v(e){const t=function(e){return`[${c}="${d(e)}"]`}(e);return 1===y(t).length?t:null}var g;function b(e,t){return"object"==typeof e&&null!==e&&t in e}function w(e){return!b(e,"disabled")||!e.disabled}function E(e){return!!w(e)&&"none"!==window.getComputedStyle(e).getPropertyValue("pointer-events")}function S(e){if(e.hidden)return!1;const t=window.getComputedStyle(e);return"hidden"!==t.getPropertyValue("visibility")&&"0"!==t.getPropertyValue("opacity")&&"none"!==t.getPropertyValue("display")&&0!==e.offsetWidth&&0!==e.offsetHeight}function T(e){return w(e)&&E(e)&&S(e)}function C(e){return"INPUT"!==e.tagName&&!e.innerHTML.length}!function(e){e.Reloading="Reloading",e.Done="Done",e.UnhandledError="UnhandledError",e.Timeout="Timeout",e.NoRequiredSelectorsProvided="NoRequiredSelectorsProvided",e.ApplyAndRemoveButtonsHaveSameSelector="ApplyAndRemoveButtonsHaveSameSelector"}(g||(g={}));const P=1e3;function B(e=.5){return new Promise((t=>setTimeout(t,e*P)))}function A(e){e.dispatchEvent(new PointerEvent("pointerdown",{bubbles:!0,pointerType:"mouse"})),e.dispatchEvent(new MouseEvent("mousedown",{bubbles:!0})),e.dispatchEvent(new PointerEvent("pointerup",{bubbles:!0,pointerType:"mouse"})),e.dispatchEvent(new MouseEvent("mouseup",{bubbles:!0})),e.dispatchEvent(new PointerEvent("click",{bubbles:!0,cancelable:!0,pointerType:"mouse"}))}function M(e){return!!e&&Boolean(h(e))}async function I(e,t){async function n(t=0){if(t>=4)throw g.Timeout;const o=e.couponInput&&h(e.couponInput);if(o&&T(o))return;if(!e.showFormButton)return;const i=h(e.showFormButton);return i&&T(i)&&(r.info("Trying to show the coupon form"),A(i)),await B(),n(t+1)}async function o(n=0){if(n>=10)return;const i=e.couponInput?h(e.couponInput):null;if(!(i&&(a=i,b(a,"value")&&T(a))))return o(n+1);var a;r.info("Trying to fill in the code"),function(e,t){const{value:n}=e;if(e.value=t,b(e,"_valueTracker")&&e._valueTracker){const t=e._valueTracker;b(t,"setValue")&&"function"==typeof t.setValue&&t.setValue(n)}e.dispatchEvent(new KeyboardEvent("keydown",{bubbles:!0})),e.dispatchEvent(new KeyboardEvent("keypress",{bubbles:!0})),e.dispatchEvent(new KeyboardEvent("input",{bubbles:!0})),e.dispatchEvent(new KeyboardEvent("keyup",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0}))}(i,t),await B();const l=e.applyButton?h(e.applyButton):null;return l&&T(l)?(r.info("Trying to submit the code"),void A(l)):o(n+1)}function i(){const[t,n]=function(){const t={pending:!0};return[(async()=>{for(let n=0;n<4;n++){const n=[e.error,e.removeButton,e.appliedCode];if(!t.pending||n.some(M))break;r.info("Waiting for feedback"),await B()}})(),()=>{t.pending=!1}]}(),[o,i]=e.loading?function(e){const t={bodyObserver:null,isLoading:M(e)};return[new Promise((n=>{t.bodyObserver=new MutationObserver((()=>{M(e)?t.isLoading=!0:t.isLoading&&n()})),t.bodyObserver.observe(document.body,{childList:!0,subtree:!0})})),()=>t.bodyObserver?.disconnect()]}(e.loading):[void 0,()=>{}],a=[t,o].filter(Boolean),l=[n,i];return Promise.race(a).finally((()=>{l.forEach((e=>e()))}))}async function a(t=0){if(e.totalAmount){if(t>=4)throw g.Timeout;if(!h(e.totalAmount))return r.info("Waiting for total price"),await B(),a(t+1)}}async function l(t=0,n=0){if(!e.closeModal)return;if(t>=4)throw g.Timeout;const o=h(e.closeModal);if(!o||!T(o)){if(t>0||n>=4)return;return await B(),l(t,n+1)}return r.info("Trying to close modal"),A(o),await B(),l(t+1)}return new Promise((u=>{const s=()=>{r.info("Page is about to reload."),u({type:g.Reloading})};(async()=>{try{if(!e.couponInput||!e.applyButton)throw g.NoRequiredSelectorsProvided;r.info(`Preparing to apply code: ${t}`),window.addEventListener("beforeunload",s),await n(),await o(),await i(),await l(),await a(),r.info(`Code: ${t} applied.`),u({type:g.Done})}catch(e){const n=function(e){switch(e){case g.Reloading:return g.Reloading;case g.Timeout:return g.Timeout;case g.NoRequiredSelectorsProvided:return g.NoRequiredSelectorsProvided;default:return g.UnhandledError}}(e);r.error(`Failed to apply code: ${t} -- ${n}`,e),u({type:n})}finally{window.removeEventListener("beforeunload",s),r.info("beforeunload listener removed.")}})()}))}async function N(e=500){return new Promise((t=>setTimeout(t,e)))}var R,$;function k(e){const t=e.toLowerCase().replace(/^https?:\/\//,"").replace(/:\d+.*/,"").replace(/(:|\/|\?|#).*/,"");if(!/[a-z0-9-.]+/.test(t))throw new Error(`Cannot get main domain from ${e}`);const[n,o,r]=t.split(".").reverse();if("localhost"===n)return n;if(!n||n.length<2)throw new Error(`Wrong root domain "${n}" in ${e}`);if(!o)throw new Error(`Unknown main domain "${o}" in ${e}`);if(!["co.uk","co.za","com.au","com.de","org.uk","uk.com","com.br","com.pl","com.nl","com.mx"].includes(`${o}.${n}`))return`${o}.${n}`;if(!r)throw new Error(`Unknown main domain "${r}" in ${e}`);return`${r}.${o}.${n}`}function F(e){try{if(!e)return{html:"",isClickable:!1,isEmpty:!0,isEnabled:!1,isVisible:!1,multipleMatches:!1,result:$.NoSelectorProvided};const t=y(e),[n]=t;return n?{html:n.outerHTML,isClickable:Boolean(t.filter(E).length),isEmpty:C(n),isEnabled:Boolean(t.filter(w).length),isVisible:Boolean(t.filter(S).length),multipleMatches:t.length>1,result:$.ElementFound}:{html:"",isClickable:!1,isEmpty:!0,isEnabled:!1,isVisible:!1,multipleMatches:!1,result:$.NoElementsFound}}catch(e){return e instanceof Error&&"SyntaxError"===e.name?(r.error($.InvalidCSSSelector,e),{html:"",isClickable:!1,isEmpty:!0,isEnabled:!1,isVisible:!1,multipleMatches:!1,result:$.InvalidCSSSelector}):(r.error($.Unhandled,e),{html:"",isClickable:!1,isEmpty:!0,isEnabled:!1,isVisible:!1,multipleMatches:!1,result:$.Unhandled})}}function V(e){if(!e)return!1;const t=e.totalAmount?y(e.totalAmount):[],n=e.couponInput?y(e.couponInput).filter(T):[],o=e.applyButton?y(e.applyButton).filter(S):[],r=e.showFormButton?y(e.showFormButton).filter(T):[];return Boolean(n.length)&&Boolean(o.length)&&Boolean(t.length)||Boolean(t.length)&&Boolean(r.length)}function L(e){if(!e||!e.removeButton)return!1;const t=y(e.removeButton).filter(T);return Boolean(t.length)}function U(e){try{if(!e)return{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:$.NoSelectorProvided};const t=y(e),[n]=t;return n?{amount:function(e){if(!e)throw new Error("Cannot parse amount from empty value");if("string"!=typeof e)throw new Error(`Cannot parse amount from "${typeof e}"`);if(!e.match(/\d/))throw new Error(`Amount not found in "${e}"`);let t,n=e.replace(/[^0-9,.]/g,""),o=0;function a(e){t&&t!==e?r.error(`Amount has conflicting types: ${t} and ${e}`):t=e}return n.match(/^\d{1,3}(?:\.\d{3})*(?:,\d{2})?$/)&&(n=n.replaceAll(".","").replace(",",".")),n.match(/^\d{1,3}(?:,\d{3})*(?:.\d{2})?$/)&&(n=n.replaceAll(",","")),(n.match(/^\d*(?:,\d{2})?$/)||n.match(/^\d*(?:,\d{1})?$/))&&(n=n.replaceAll(",",".")),o=parseFloat(n.replace(/([^0-9.])/g,"")),(e.includes("€")||e.includes("EUR"))&&a(i.Euro),e.includes("$")&&(e.includes("R$")?a(i.Real):a(i.Dollar)),e.includes("£")&&a(i.Pound),e.includes("%")&&a(i.Percent),(e.includes("zł")||e.includes("PLN"))&&a(i.Zloty),t?{type:t,value:o}:{value:o}}(n.innerText),html:n.outerHTML,isEmpty:C(n),isVisible:Boolean(t.filter(S).length),multipleMatches:t.length>1,result:$.ElementFound}:{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:$.NoElementsFound}}catch(e){return e instanceof Error&&"SyntaxError"===e.name?(r.error($.InvalidCSSSelector,e),{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:$.InvalidCSSSelector}):(r.error($.Unhandled,e),{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:$.Unhandled})}}function D(e){try{if(!e)return{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:$.NoSelectorProvided,value:""};const t=y(e),[n]=t;return n?{html:n.outerHTML,isEmpty:C(n),isVisible:Boolean(t.filter(S).length),multipleMatches:t.length>1,result:$.ElementFound,value:n.innerHTML}:{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:$.NoElementsFound,value:""}}catch(e){return e instanceof Error&&"SyntaxError"===e.name?(r.error($.InvalidCSSSelector,e),{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:$.InvalidCSSSelector,value:""}):(r.error($.Unhandled,e),{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:$.Unhandled,value:""})}}function O(){return window.location.href}!function(e){e.GetPageState="caa-get-page-state",e.ApplyCode="caa-apply-code",e.RemoveCode="caa-remove-code"}(R||(R={})),function(e){e.ElementFound="ElementFound",e.NoSelectorProvided="NoSelectorProvided",e.Unhandled="Unhandled",e.NoElementsFound="NoElementsFound",e.InvalidCSSSelector="InvalidCSSSelector",e.NoConfigProvided="NoConfigProvided"}($||($={}));const x=function(){try{return"undefined"!=typeof browser?browser:chrome}catch{return console.warn("[CAA-ENGINE]: not running in a DOM environment, the browser object is not defined."),{}}}();function H({logger:e=(()=>{})}={}){x.runtime.onMessage.addListener(((t,n,i)=>{switch(o(e),t.type){case R.GetPageState:return async function(e){return{amounts:{discount:U(e.discountAmount),subtotal:U(e.subtotalAmount),total:U(e.totalAmount)},coupon:{appliedCode:D(e.appliedCode),canApply:V(e),canRemove:L(e)},currentUrl:O(),elements:{applyButton:F(e.applyButton),closeModal:F(e.closeModal),couponInput:F(e.couponInput),error:F(e.error),loading:F(e.loading),removeButton:F(e.removeButton),showFormButton:F(e.showFormButton)},mainDomain:k(O())}}(t.config).then(i),!0;case R.ApplyCode:return I(t.config,t.code).then(i),!0;case R.RemoveCode:return async function(e){let t=!1;try{if(!e.removeButton)throw g.NoRequiredSelectorsProvided;if(e.removeButton===e.applyButton)throw g.ApplyAndRemoveButtonsHaveSameSelector;return r.info("Trying to remove applied code."),window.addEventListener("beforeunload",n),await async function n(o=0){if(o>=4)throw g.Timeout;if(t)throw g.Reloading;if(!e.removeButton)return;const i=h(e.removeButton);return i&&T(i)?(A(i),r.info("Waiting for coupon is removed"),await N(),n(o+1)):void 0}(),r.info("Code removed."),{type:g.Done}}catch(e){let t;switch(r.error("Failed to remove the code",e),e){case g.Reloading:t=g.Reloading;break;case g.ApplyAndRemoveButtonsHaveSameSelector:t=g.ApplyAndRemoveButtonsHaveSameSelector;break;default:t=g.UnhandledError}return{type:t}}finally{window.removeEventListener("beforeunload",n),r.info("beforeunload listener removed.")}function n(){r.info("Page is about to reload."),t=!0}}(t.config).then(i),!0}}))}var q,j,G,W;async function z(e,t,n=1e4){return new Promise((async o=>{let i=!1;const a=setTimeout((()=>{i=!0,o(null)}),n);for(;!i;){try{const n=await x.tabs.sendMessage(e,{config:t,type:R.GetPageState});if(n)return clearTimeout(a),void o(n)}catch(e){r.error("get caa page state",e)}await N(200)}}))}async function _(e,t,n){const o=await z(e,n);if(!o)return{...t,type:q.Invalid};let i=o.amounts.total.amount;if(!i)return{...t,type:q.Invalid};if(o.elements.removeButton.isClickable){try{await async function(e,t){let n=10;try{await x.tabs.sendMessage(e,{config:t,type:R.RemoveCode})}catch(e){r.error("remove caa-engine error",e)}for(;n>0;){n--;const o=await z(e,t);if(o){if(!o.elements.removeButton.isVisible)return;await N(200)}}if(!n)throw new Error("remove code is not removed")}(e,n)}catch(e){return r.error("remove code caa-background",e),{...t,type:q.Invalid}}const o=await z(e,n);if(!o)return{...t,type:q.Invalid};!o.elements.removeButton.isVisible&&o.amounts.total.amount&&(i=o.amounts.total.amount)}try{const o=await x.tabs.sendMessage(e,{code:t.code,config:n,type:R.ApplyCode});r.info({codeApplicationResult:o})}catch(e){r.error("apply code caa-from-content",e)}let a=10;for(;a>0;){a--;const o=await z(e,n);if(!o)continue;const r=o.amounts.total.amount;if(r){if(r.value<i.value)return{...t,initialTotal:i,totalWithDiscount:r,type:q.Discount};await N(200)}}return r.info("timeout handleApplyProcess"),{...t,type:q.Invalid}}!function(e){e.Discount="Discount",e.Invalid="Invalid"}(q||(q={})),function(e){e.TryCodes="caa-try-codes",e.Stop="caa-stop",e.GetPageState="caa-get-page-state"}(j||(j={})),function(e){e.CodeTested="caa-code-tested"}(G||(G={})),function(e){e.PageLoaded="caa-page-loaded"}(W||(W={}));const K=new Map;async function J(e,t){const n=k(e),o=new URL(e).pathname,r=t(n),i=await async function(e,t){const n=K.get(e);if(n?.length)return n;const o=await fetch(t).then((e=>e.json())).then(Z).catch((()=>[]));return K.set(e,o),o}(n,r).then(Q);let a=null,l=null;for(const e of i)e.urlPattern?new RegExp(e.urlPattern).test(o)&&(l=e):a=e;if(l)return l;if(a)return a;throw new Error(`No config found for ${n}`)}function Z(e){const t=e,n=[];for(const e of t.configs){const t=e;t.data&&(t.disabled||n.push({appliedCode:t.data.appliedCode||void 0,applyButton:t.data.applyButton||void 0,applyType:t.data.applyType||void 0,closeModal:t.data.closeModal||void 0,couponInput:t.data.couponInput||void 0,discountAmount:t.data.discountAmount||void 0,domain:t.data.domain||"",error:t.data.error||void 0,loading:t.data.loading||void 0,removeButton:t.data.removeButton||void 0,showFormButton:t.data.showFormButton||void 0,subtotalAmount:t.data.subtotalAmount||void 0,totalAmount:t.data.totalAmount||void 0,urlPattern:t.data.urlPattern||void 0}))}return n}function Q(e){return e.sort(((e,t)=>e.urlPattern?t.urlPattern?e.urlPattern.length-t.urlPattern.length:1:-1))}class X{active;testedCodes=new Map;constructor(){this.active=!0}get isActive(){return this.active}stop(){this.active=!1}addTestedCode(e,t){this.testedCodes.set(e,t)}getTestedCode(e){return this.testedCodes.get(e)}}function Y(e){return e.code.trim().length&&!/\s/.test(e.code.trim())}const ee=new Map;function te({getUnifiedConfigUrl:e,logger:t=(()=>()=>{})}){x.runtime.onMessage.addListener(((n,i,a)=>{const l=i.tab?.id,u=i.tab?.url;if(void 0!==l)if(o(t(l)),void 0!==u)switch(n.type){case W.PageLoaded:return void r.info({message:n,tabId:l});case j.Stop:return r.info({message:n,tabId:l}),ee.get(l)?.stop(),void r.info("stopping CAA for tab"+l);case j.TryCodes:return r.info({message:n,tabId:l}),void async function(e,t,n,{codes:o,cacheDuplicates:i=!1,validateCodes:a=!1,minDelay:l=1e3,config:u}){let s;try{s=u||await J(t,n)}catch(e){return void r.error("Cannot get config for "+t,e)}r.info("starting CAA for tab "+e);const c=new X;ee.set(e,c);for(const t of o){if(!c.isActive)break;const n=c.getTestedCode(t.code);if(i&&n){await N(l),await ne(e,{...n,...t});continue}if(a&&!Y(t)){await N(l),await ne(e,{...t,type:q.Invalid});continue}const o=(new Date).getTime(),u=await _(e,t,s);r.perf(t.code+" tested in: ",{code:t.code,timeSpent:(new Date).getTime()-o}),c.addTestedCode(t.code,u),await ne(e,u)}ee.delete(e)}(l,u,e,n);case j.GetPageState:return r.info({message:n,tabId:l}),async function(e,t,n,o){let i;if(o)i=o;else try{i=await J(t,n)}catch(e){return void r.error("No config exists for: "+t,e)}const a=await z(e,i);return r.info({pageState:a,tabId:e}),a}(l,u,e,n.config).then(a),!0}else r.error("No tabUrl provided for "+l);else console.error("No tabId provided")}))}async function ne(e,t){r.info({code:t,info:"sending tried code",tabId:e});const n={code:t,type:G.CodeTested};let o=!1;for(let i=0;i<10;i++){try{await oe(e),o=await x.tabs.sendMessage(e,n)}catch(n){r.info({code:t,info:"Tried code not received by the tab.",tabId:e})}if(o)break;await N(200)}if(!o)throw new Error(`Cannot send tried code to the browser tab. code: ${t.code} , tabId: ${e}`)}async function oe(e){let t=10;for(;t--;){if("complete"===(await x.tabs.get(e)).status)return;await N(100)}}module.exports=t})(); | ||
(()=>{"use strict";var e={d:(t,n)=>{for(var o in n)e.o(n,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:n[o]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{AmountType:()=>i,BackgroundToClientMessageType:()=>W,ClientToBackgroundMessageType:()=>G,TestedCodeType:()=>q,getElements:()=>y,getGeneratedSelector:()=>v,getMainDomain:()=>F,setupBackgroundListeners:()=>oe,setupContentListeners:()=>j});let n=()=>{};function o(e){n=e}const r={error:(e,t)=>n({level:"ERROR",message:e,stack:t instanceof Error&&t.stack||(new Error).stack||""}),info:e=>n({details:JSON.stringify(e),level:"INFO"}),perf:(e,t)=>n({label:e,level:"PERF",meta:t})};var i;function a(e){try{const[,t=""]=e.split('"');return Object(JSON.parse(decodeURI(t)))}catch{return{}}}function l(e){return a(e)}!function(e){e.Dollar="$",e.Euro="€",e.Percent="%",e.Pound="£",e.Real="R$",e.Zloty="zł"}(i||(i={}));const s=/[0-9.,]+/g;function u(e){return e?e.normalize("NFC").replaceAll(s,""):null}const c="data-caa-text";function d({innerText:e,tagName:t}){return function(e){try{return encodeURI(JSON.stringify(e))}catch(e){return r.error("Cannot encode a custom cssSelector: ",e),""}}({innerText:e,tagName:t})}function f(e){const{tagName:t,innerText:n}=a(e);return e.includes(c)&&"string"==typeof t&&"string"==typeof n}function m(e){return f(e)}function p(e){const t=Array.from(document.querySelectorAll(e));return f(e)?t.length>0?t.filter((n=e,function(e){const{tagName:t,innerText:o}=l(n);return e.tagName===t&&u(e.innerText)===u(o)})):function(e){const{tagName:t,innerText:n}=l(e);return Array.from(document.getElementsByTagName(t)).filter((e=>e instanceof HTMLElement)).filter((e=>u(e.innerText)===u(n))).map((e=>(e.setAttribute(c,d(e)),e)))}(e):[];var n}function h(e){try{if(m(e)){const[t=null]=p(e);return t}return document.querySelector(e)}catch(t){return r.error(`Cannot find the element in the DOM with the selector="${e}":`,t),null}}function y(e){try{return m(e)?p(e):Array.from(document.querySelectorAll(e))}catch(t){return r.error(`Cannot find elements in the DOM with the selector="${e}":`,t),[]}}function v(e){const t=function(e){return`[${c}="${d(e)}"]`}(e);return 1===y(t).length?t:null}function g(e,t){return"object"==typeof e&&null!==e&&t in e}function b(e){return!g(e,"disabled")||!e.disabled}function w(e){return!!b(e)&&"none"!==window.getComputedStyle(e).getPropertyValue("pointer-events")}function E(e){if(e.hidden)return!1;const t=window.getComputedStyle(e);return"hidden"!==t.getPropertyValue("visibility")&&"0"!==t.getPropertyValue("opacity")&&"none"!==t.getPropertyValue("display")&&0!==e.offsetWidth&&0!==e.offsetHeight}function S(e){return b(e)&&w(e)&&E(e)}function T(e){return"INPUT"!==e.tagName&&!e.innerHTML.length}const C=1e3;function P(e=.5){return new Promise((t=>setTimeout(t,e*C)))}function B(e){e.dispatchEvent(new PointerEvent("pointerdown",{bubbles:!0,pointerType:"mouse"})),e.dispatchEvent(new MouseEvent("mousedown",{bubbles:!0})),e.dispatchEvent(new PointerEvent("pointerup",{bubbles:!0,pointerType:"mouse"})),e.dispatchEvent(new MouseEvent("mouseup",{bubbles:!0})),e.dispatchEvent(new PointerEvent("click",{bubbles:!0,cancelable:!0,pointerType:"mouse"}))}var A,M,I;function N(e){return!!e&&Boolean(h(e))}function R(e){const t=e&&h(e);return!!t&&E(t)}async function $(e,t){async function n(t=0){if(t>=4)throw A.Timeout;const o=e.couponInput&&h(e.couponInput);if(o&&S(o))return;if(!e.showFormButton)return;const i=h(e.showFormButton);return i&&S(i)&&(r.info("Trying to show the coupon form"),B(i)),await P(),n(t+1)}async function o(n=0){if(n>=10)return;const i=e.couponInput?h(e.couponInput):null;if(!(i&&(a=i,g(a,"value")&&S(a))))return o(n+1);var a;r.info("Trying to fill in the code"),function(e,t){const{value:n}=e;if(e.value=t,g(e,"_valueTracker")&&e._valueTracker){const t=e._valueTracker;g(t,"setValue")&&"function"==typeof t.setValue&&t.setValue(n)}e.dispatchEvent(new KeyboardEvent("keydown",{bubbles:!0})),e.dispatchEvent(new KeyboardEvent("keypress",{bubbles:!0})),e.dispatchEvent(new KeyboardEvent("input",{bubbles:!0})),e.dispatchEvent(new KeyboardEvent("keyup",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0}))}(i,t),await P();const l=e.applyButton?h(e.applyButton):null;return l&&S(l)?(r.info("Trying to submit the code"),void B(l)):o(n+1)}function i(){const[t,n]=function(){const t={pending:!0};return[(async()=>{for(let n=0;n<4;n++){const n=[e.error,e.removeButton,e.appliedCode];if(!t.pending||n.some(R))break;r.info("Waiting for feedback"),await P()}})(),()=>{t.pending=!1}]}(),[o,i]=e.loading?function(e){const t={bodyObserver:null,isLoading:N(e)};return[new Promise((n=>{t.bodyObserver=new MutationObserver((()=>{N(e)?t.isLoading=!0:t.isLoading&&n()})),t.bodyObserver.observe(document.body,{childList:!0,subtree:!0})})),()=>t.bodyObserver?.disconnect()]}(e.loading):[void 0,()=>{}],a=[t,o].filter(Boolean),l=[n,i];return Promise.race(a).finally((()=>{l.forEach((e=>e()))}))}async function a(t=0){if(e.totalAmount){if(t>=4)throw A.Timeout;if(!h(e.totalAmount))return r.info("Waiting for total price"),await P(),a(t+1)}}async function l(t=0,n=0){if(!e.closeModal)return;if(t>=4)throw A.Timeout;const o=h(e.closeModal);if(!o||!S(o)){if(t>0||n>=4)return;return await P(),l(t,n+1)}return r.info("Trying to close modal"),B(o),await P(),l(t+1)}return new Promise((s=>{const u=()=>{r.info("Page is about to reload."),s({type:A.Reloading})};(async()=>{try{if(!e.couponInput||!e.applyButton)throw A.NoRequiredSelectorsProvided;r.info(`Preparing to apply code: ${t}`),window.addEventListener("beforeunload",u),await n(),await o(),await i(),await l(),await a(),r.info(`Code: ${t} applied.`),s({type:A.Done})}catch(e){const n=function(e){switch(e){case A.Reloading:return A.Reloading;case A.Timeout:return A.Timeout;case A.NoRequiredSelectorsProvided:return A.NoRequiredSelectorsProvided;default:return A.UnhandledError}}(e);r.error(`Failed to apply code: ${t} -- ${n}`,e),s({type:n})}finally{window.removeEventListener("beforeunload",u),r.info("beforeunload listener removed.")}})()}))}async function k(e=500){return new Promise((t=>setTimeout(t,e)))}function F(e){const t=e.toLowerCase().replace(/^https?:\/\//,"").replace(/:\d+.*/,"").replace(/(:|\/|\?|#).*/,"");if(!/[a-z0-9-.]+/.test(t))throw new Error(`Cannot get main domain from ${e}`);const[n,o,r]=t.split(".").reverse();if("localhost"===n)return n;if(!n||n.length<2)throw new Error(`Wrong root domain "${n}" in ${e}`);if(!o)throw new Error(`Unknown main domain "${o}" in ${e}`);if(!["co.uk","co.za","com.au","com.de","org.uk","uk.com","com.br","com.pl","com.nl","com.mx","com.at","co.at"].includes(`${o}.${n}`))return`${o}.${n}`;if(!r)throw new Error(`Unknown main domain "${r}" in ${e}`);return`${r}.${o}.${n}`}function V(e){try{if(!e)return{html:"",isClickable:!1,isEmpty:!0,isEnabled:!1,isVisible:!1,multipleMatches:!1,result:I.NoSelectorProvided};const t=y(e),[n]=t;return n?{html:n.outerHTML,isClickable:Boolean(t.filter(w).length),isEmpty:T(n),isEnabled:Boolean(t.filter(b).length),isVisible:Boolean(t.filter(E).length),multipleMatches:t.length>1,result:I.ElementFound}:{html:"",isClickable:!1,isEmpty:!0,isEnabled:!1,isVisible:!1,multipleMatches:!1,result:I.NoElementsFound}}catch(e){return e instanceof Error&&"SyntaxError"===e.name?(r.error(I.InvalidCSSSelector,e),{html:"",isClickable:!1,isEmpty:!0,isEnabled:!1,isVisible:!1,multipleMatches:!1,result:I.InvalidCSSSelector}):(r.error(I.Unhandled,e),{html:"",isClickable:!1,isEmpty:!0,isEnabled:!1,isVisible:!1,multipleMatches:!1,result:I.Unhandled})}}function L(e){if(!e)return!1;const t=e.totalAmount?y(e.totalAmount):[],n=e.couponInput?y(e.couponInput).filter(S):[],o=e.applyButton?y(e.applyButton).filter(E):[],r=e.showFormButton?y(e.showFormButton).filter(S):[];return Boolean(n.length)&&Boolean(o.length)&&Boolean(t.length)||Boolean(t.length)&&Boolean(r.length)}function U(e){if(!e||!e.removeButton)return!1;const t=y(e.removeButton).filter(S);return Boolean(t.length)}function D(e){try{if(!e)return{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:I.NoSelectorProvided};const t=y(e),[n]=t;return n?{amount:function(e){if(!e)throw new Error("Cannot parse amount from empty value");if("string"!=typeof e)throw new Error(`Cannot parse amount from "${typeof e}"`);if(!e.match(/\d/))throw new Error(`Amount not found in "${e}"`);let t,n=e.replace(/[^0-9,.]/g,""),o=0;function a(e){t&&t!==e?r.error(`Amount has conflicting types: ${t} and ${e}`):t=e}return n.match(/^\d{1,3}(?:\.\d{3})*(?:,\d{2})?$/)&&(n=n.replaceAll(".","").replace(",",".")),n.match(/^\d{1,3}(?:,\d{3})*(?:.\d{2})?$/)&&(n=n.replaceAll(",","")),(n.match(/^\d*(?:,\d{2})?$/)||n.match(/^\d*(?:,\d{1})?$/))&&(n=n.replaceAll(",",".")),o=parseFloat(n.replace(/([^0-9.])/g,"")),(e.includes("€")||e.includes("EUR"))&&a(i.Euro),e.includes("$")&&(e.includes("R$")?a(i.Real):a(i.Dollar)),e.includes("£")&&a(i.Pound),e.includes("%")&&a(i.Percent),(e.includes("zł")||e.includes("PLN"))&&a(i.Zloty),t?{type:t,value:o}:{value:o}}(n.innerText),html:n.outerHTML,isEmpty:T(n),isVisible:Boolean(t.filter(E).length),multipleMatches:t.length>1,result:I.ElementFound}:{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:I.NoElementsFound}}catch(e){return e instanceof Error&&"SyntaxError"===e.name?(r.error(I.InvalidCSSSelector,e),{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:I.InvalidCSSSelector}):(r.error(I.Unhandled,e),{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:I.Unhandled})}}function O(e){try{if(!e)return{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:I.NoSelectorProvided,value:""};const t=y(e),[n]=t;return n?{html:n.outerHTML,isEmpty:T(n),isVisible:Boolean(t.filter(E).length),multipleMatches:t.length>1,result:I.ElementFound,value:n.innerHTML}:{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:I.NoElementsFound,value:""}}catch(e){return e instanceof Error&&"SyntaxError"===e.name?(r.error(I.InvalidCSSSelector,e),{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:I.InvalidCSSSelector,value:""}):(r.error(I.Unhandled,e),{html:"",isEmpty:!0,isVisible:!1,multipleMatches:!1,result:I.Unhandled,value:""})}}function x(){return window.location.href}!function(e){e.Reloading="Reloading",e.Done="Done",e.UnhandledError="UnhandledError",e.Timeout="Timeout",e.NoRequiredSelectorsProvided="NoRequiredSelectorsProvided",e.ApplyAndRemoveButtonsHaveSameSelector="ApplyAndRemoveButtonsHaveSameSelector"}(A||(A={})),function(e){e.GetPageState="caa-get-page-state",e.ApplyCode="caa-apply-code",e.RemoveCode="caa-remove-code"}(M||(M={})),function(e){e.ElementFound="ElementFound",e.NoSelectorProvided="NoSelectorProvided",e.Unhandled="Unhandled",e.NoElementsFound="NoElementsFound",e.InvalidCSSSelector="InvalidCSSSelector",e.NoConfigProvided="NoConfigProvided"}(I||(I={}));const H=function(){try{return"object"==typeof browser&&null!==browser&&"runtime"in browser?browser:chrome}catch{return console.warn("[CAA-ENGINE]: not running in a DOM environment, the browser object is not defined."),{}}}();function j({logger:e=(()=>{})}={}){H.runtime.onMessage.addListener(((t,n,i)=>{switch(o(e),t.type){case M.GetPageState:return async function(e){return{amounts:{discount:D(e.discountAmount),subtotal:D(e.subtotalAmount),total:D(e.totalAmount)},coupon:{appliedCode:O(e.appliedCode),canApply:L(e),canRemove:U(e)},currentUrl:x(),elements:{applyButton:V(e.applyButton),closeModal:V(e.closeModal),couponInput:V(e.couponInput),error:V(e.error),loading:V(e.loading),removeButton:V(e.removeButton),showFormButton:V(e.showFormButton)},mainDomain:F(x())}}(t.config).then(i),!0;case M.ApplyCode:return $(t.config,t.code).then(i),!0;case M.RemoveCode:return async function(e){let t=!1;try{if(!e.removeButton)throw A.NoRequiredSelectorsProvided;if(e.removeButton===e.applyButton)throw A.ApplyAndRemoveButtonsHaveSameSelector;return r.info("Trying to remove applied code."),window.addEventListener("beforeunload",n),await async function n(o=0){if(o>=4)throw A.Timeout;if(t)throw A.Reloading;if(!e.removeButton)return;const i=h(e.removeButton);return i&&S(i)?(B(i),r.info("Waiting for coupon is removed"),await k(),n(o+1)):void 0}(),r.info("Code removed."),{type:A.Done}}catch(e){let t;switch(r.error("Failed to remove the code",e),e){case A.Reloading:t=A.Reloading;break;case A.ApplyAndRemoveButtonsHaveSameSelector:t=A.ApplyAndRemoveButtonsHaveSameSelector;break;default:t=A.UnhandledError}return{type:t}}finally{window.removeEventListener("beforeunload",n),r.info("beforeunload listener removed.")}function n(){r.info("Page is about to reload."),t=!0}}(t.config).then(i),!0}}))}var q,G,W,z;!function(e){e.Discount="Discount",e.Invalid="Invalid"}(q||(q={})),function(e){e.TryCodes="caa-try-codes",e.Stop="caa-stop",e.GetPageState="caa-get-page-state"}(G||(G={})),function(e){e.CodeTested="caa-code-tested"}(W||(W={})),function(e){e.PageLoaded="caa-page-loaded"}(z||(z={}));const _=1e4;async function K(e,t,n=_){return new Promise((async o=>{let i=!1;const a=setTimeout((()=>{i=!0,o(null)}),n);for(;!i;){try{const n=await H.tabs.sendMessage(e,{config:t,type:M.GetPageState});if(n)return clearTimeout(a),void o(n)}catch(e){r.error("get caa page state",e)}await k(200)}}))}async function J(e,t,n,o=_){const i=await K(e,n,o);if(!i)return{...t,type:q.Invalid};let a=i.amounts.total.amount;if(!a)return{...t,type:q.Invalid};if(i.elements.removeButton.isClickable){try{await async function(e,t){let n=10;try{await H.tabs.sendMessage(e,{config:t,type:M.RemoveCode})}catch(e){r.error("remove caa-engine error",e)}for(;n>0;){n--;const o=await K(e,t);if(o){if(!o.elements.removeButton.isVisible)return;await k(200)}}if(!n)throw new Error("remove code is not removed")}(e,n)}catch(e){return r.error("remove code caa-background",e),{...t,type:q.Invalid}}const i=await K(e,n,o);if(!i)return{...t,type:q.Invalid};!i.elements.removeButton.isVisible&&i.amounts.total.amount&&(a=i.amounts.total.amount)}try{const o=await H.tabs.sendMessage(e,{code:t.code,config:n,type:M.ApplyCode});r.info({codeApplicationResult:o})}catch(e){r.error("apply code caa-from-content",e)}let l=10;for(;l>0;){l--;const r=await K(e,n,o);if(!r)continue;const i=r.amounts.total.amount;if(i){if(i.value<a.value)return{...t,initialTotal:a,totalWithDiscount:i,type:q.Discount};await k(200)}}return r.info("timeout handleApplyProcess"),{...t,type:q.Invalid}}const Z=new Map;async function Q(e,t){const n=F(e),o=new URL(e).pathname,r=t(n),i=await async function(e,t){const n=Z.get(e);if(n?.length)return n;const o=await fetch(t).then((e=>e.json())).then(X).catch((()=>[]));return Z.set(e,o),o}(n,r).then(Y);let a=null,l=null;for(const e of i)e.urlPattern?new RegExp(e.urlPattern).test(o)&&(l=e):a=e;if(l)return l;if(a)return a;throw new Error(`No config found for ${n}`)}function X(e){const t=e,n=[];for(const e of t.configs){const t=e;t.data&&(t.disabled||n.push({appliedCode:t.data.appliedCode||void 0,applyButton:t.data.applyButton||void 0,applyType:t.data.applyType||void 0,closeModal:t.data.closeModal||void 0,couponInput:t.data.couponInput||void 0,discountAmount:t.data.discountAmount||void 0,domain:t.data.domain||"",error:t.data.error||void 0,loading:t.data.loading||void 0,removeButton:t.data.removeButton||void 0,showFormButton:t.data.showFormButton||void 0,subtotalAmount:t.data.subtotalAmount||void 0,totalAmount:t.data.totalAmount||void 0,urlPattern:t.data.urlPattern||void 0}))}return n}function Y(e){return e.sort(((e,t)=>e.urlPattern?t.urlPattern?e.urlPattern.length-t.urlPattern.length:1:-1))}class ee{active;testedCodes=new Map;constructor(){this.active=!0}get isActive(){return this.active}stop(){this.active=!1}addTestedCode(e,t){this.testedCodes.set(e,t)}getTestedCode(e){return this.testedCodes.get(e)}}function te(e){return e.code.trim().length&&!/\s/.test(e.code.trim())}const ne=new Map;function oe({getUnifiedConfigUrl:e,logger:t=(()=>()=>{})}){H.runtime.onMessage.addListener(((n,i,a)=>{const l=i.tab?.id,s=i.tab?.url;if(void 0!==l)if(o(t(l)),void 0!==s)switch(n.type){case z.PageLoaded:return void r.info({message:n,tabId:l});case G.Stop:return r.info({message:n,tabId:l}),ne.get(l)?.stop(),void r.info("stopping CAA for tab"+l);case G.TryCodes:return r.info({message:n,tabId:l}),void async function(e,t,n,{codes:o,cacheDuplicates:i=!1,validateCodes:a=!1,minDelay:l=1e3,config:s}){let u;try{u=s||await Q(t,n)}catch(e){return void r.error("Cannot get config for "+t,e)}r.info("starting CAA for tab "+e);const c=new ee;ne.set(e,c);for(const t of o){if(!c.isActive)break;const n=c.getTestedCode(t.code);if(i&&n){await k(l),await re(e,{...n,...t});continue}if(a&&!te(t)){await k(l),await re(e,{...t,type:q.Invalid});continue}const o=(new Date).getTime(),s=await J(e,t,u);r.perf(t.code+" tested in: ",{code:t.code,timeSpent:(new Date).getTime()-o}),c.addTestedCode(t.code,s),await re(e,s)}ne.delete(e)}(l,s,e,n);case G.GetPageState:return r.info({message:n,tabId:l}),async function(e,t,n,o){let i;if(o)i=o;else try{i=await Q(t,n)}catch(e){return void r.error("No config exists for: "+t,e)}const a=await K(e,i);return r.info({pageState:a,tabId:e}),a}(l,s,e,n.config).then(a),!0}else r.error("No tabUrl provided for "+l);else console.error("No tabId provided")}))}async function re(e,t){r.info({code:t,info:"sending tried code",tabId:e});const n={code:t,type:W.CodeTested};let o=!1;for(let i=0;i<10;i++){try{await ie(e),o=await H.tabs.sendMessage(e,n)}catch(n){r.info({code:t,info:"Tried code not received by the tab.",tabId:e})}if(o)break;await k(200)}if(!o)throw new Error(`Cannot send tried code to the browser tab. code: ${t.code} , tabId: ${e}`)}async function ie(e){let t=10;for(;t--;){if("complete"===(await H.tabs.get(e)).status)return;await k(100)}}module.exports=t})(); |
@@ -12,4 +12,6 @@ { | ||
}, | ||
"main": "dist/index.js", | ||
"module": "dist/index.mjs", | ||
"name": "@global-savings-group/caa-engine", | ||
"version": "4.0.5" | ||
"version": "4.0.7" | ||
} |
Sorry, the diff of this file is not supported yet
51511
44
349