@topsort/analytics.js
Advanced tools
+11
-0
@@ -9,2 +9,13 @@ # Changelog | ||
| ## Version 2.2.0 (2023-11-13) | ||
| ### Added | ||
| - support passing `additionalAttribution` | ||
| ### Refactor | ||
| - Stop publishing to codebuild/s3 | ||
| - Update dependencies | ||
| ## Version 2.1.0 (2023-08-30) | ||
@@ -11,0 +22,0 @@ |
@@ -11,2 +11,3 @@ interface Placement { | ||
| entity?: Entity; | ||
| additionalAttribution?: Entity; | ||
| placement: Placement; | ||
@@ -20,2 +21,3 @@ occurredAt: string; | ||
| entity?: Entity; | ||
| additionalAttribution?: Entity; | ||
| placement: Placement; | ||
@@ -22,0 +24,0 @@ occurredAt: string; |
@@ -18,1 +18,9 @@ export interface Store<T> { | ||
| } | ||
| export declare class BidStore { | ||
| private _key; | ||
| private _storage; | ||
| private _bid; | ||
| constructor(key: string); | ||
| get(): string | undefined; | ||
| set(bid: string): void; | ||
| } |
+1
-1
@@ -1,1 +0,1 @@ | ||
| (function(d){typeof define=="function"&&define.amd?define(d):d()})(function(){"use strict";class d{constructor(){this._data=[]}get(){return this._data}set(e){this._data=e}}class m{constructor(e){this._key=e,this._storage=window.localStorage}get(){const e=this._storage.getItem(this._key);return e?JSON.parse(e):[]}set(e){this._storage.setItem(this._key,JSON.stringify(e))}}const O="ts-t",M="ts-q",N=250,v=3,P=25,A=250,_=9,R=0;function L(t,e){return e>0?t+(Math.random()+Math.pow(2,e))*1e3:0}function U(){var e;const t=new m(O);try{const s="3";if(t.set([{x:s}]),((e=t.get()[0])==null?void 0:e.x)===s)return new m(M)}catch{}return new d}class C{constructor(e){this._store=U(),this._processing=new Set,this._scheduled=!1,this._processor=e}append(e,s){let n=this._store.get();n.push({e,r:0,p:s!=null&&s.highPriority?_:R}),n=n.slice(-N),this._setEntries(n)}async _processNow(e){if(!e.length)return;const s=[];for(let i=e.length-1;i>=0&&s.length<P;i--){const c=e[i],l=c==null?void 0:c.e;l&&!this._processing.has(l.id)&&L(l.t,c.r)<=Date.now()&&(s.push(l),this._processing.add(l.id))}if(!s.length){this._scheduleProcessing();return}let n={done:new Set,retry:new Set};try{n=await this._processor(s)}catch{for(const c of s)n.done.add(c.id)}const o=[];for(const i of this._processing)s.find(c=>c.id===i)||o.push(i);this._processing=new Set(o);const r=this._store.get(),g=[];for(const i of r)n.done.has(i.e.id)||(n.retry.has(i.e.id)?i.r<v&&(i.r+=1,g.push(i)):g.push(i));this._setEntries(g)}_setEntries(e){this._store.set(e),e.length&&(e.some(s=>s.p===_)||this._store instanceof d?this._processNow(e):this._scheduleProcessing())}_scheduleProcessing(){this._scheduled||(this._scheduled=!0,setTimeout(()=>{this._scheduled=!1,this._processNow(this._store.get())},A))}}const q="2.1.0";async function x(t,e){try{const s=(e.url||"https://api.topsort.com")+"/v2/events",n=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json","X-UA":`ts.js/${q}`,Authorization:"Bearer "+e.token},body:JSON.stringify(t),keepalive:!0});return{ok:n.ok,retry:n.status===429||n.status>=500}}catch{return{ok:!1,retry:!0}}}const S=2500,H=.5;let a=new Set;function I(){var t,e;return((e=(t=window.URL).createObjectURL)==null?void 0:e.call(t,new Blob).split("/").pop())||Math.random()+""}let u;function w(){if(u)return u;const t=B();if(t)return u=t,t;const e=I();return E(e),e}function E(t){const e=window.TS.cookieName||"tsuid";u=t,document.cookie=e+"="+t+";max-age=31536000"}function D(){return u=void 0,document.cookie="tsuid=",w()}window.TS.setUserId=E,window.TS.getUserId=w,window.TS.resetUserId=D;function B(){var s;const t=window.TS.cookieName||"tsuid";return(s=new RegExp("(^|;)\\s*"+t+"\\s*=\\s*([^;]+)").exec(document.cookie))==null?void 0:s.pop()}function X(t){const e=t.type,s={path:t.page};let n;t.product&&(n={type:"product",id:t.product});const o=new Date(t.t).toISOString();switch(e){case"Click":return{clicks:[{resolvedBidId:t.bid,entity:n,placement:s,occurredAt:o,opaqueUserId:t.uid,id:t.id}]};case"Impression":return{impressions:[{resolvedBidId:t.bid,entity:n,placement:s,occurredAt:o,opaqueUserId:t.uid,id:t.id}]};case"Purchase":return{purchases:[{occurredAt:o,opaqueUserId:t.uid,items:(t.items||[]).map(r=>({productId:r.product,quantity:r.quantity,unitPrice:r.price})),id:t.id}]}}}async function j(t){const e={done:new Set,retry:new Set},s=[];for(const n of t)s.push(x(X(n),window.TS).then(o=>{(o.retry?e.retry:e.done).add(n.id)}).catch(()=>{e.done.add(n.id)}));return await Promise.all(s),e}const z=new C(j);function h(t,e){const s=J(t);if(a.has(s))return;if(a.add(s),a.size>S){const o=a.values();for(let r=0;r<a.size-S;--r)o.next();a=new Set(o)}z.append(t);const n=new CustomEvent("topsort",{bubbles:!0,detail:t});e.dispatchEvent(n)}function J(t){return[t.page,t.type,t.product,t.bid].join("-")}function Y(){const t=window.location,e=t.hash;return e[1]==="/"?e:t.pathname}function f(t,e){const s=e.dataset.tsProduct,n=e.dataset.tsResolvedBid,o={type:t,product:s,bid:n,t:Date.now(),page:Y(),id:I(),uid:w()};return t==="Purchase"&&(o.items=JSON.parse(e.dataset.tsItems||"[]")),o}function G(t){if(!(t.currentTarget instanceof HTMLElement))return;const e=t.currentTarget.closest(y);e&&e instanceof HTMLElement&&h(f("Click",e),e)}const p=window.IntersectionObserver?new IntersectionObserver(t=>{for(const e of t)if(e.isIntersecting){const s=e.target;s instanceof HTMLElement&&(h(f("Impression",s),s),p&&p.unobserve(s))}},{threshold:H}):void 0,y="[data-ts-product],[data-ts-action],[data-ts-items],[data-ts-resolved-bid]";function K(t){const e=t.querySelectorAll("[data-ts-clickable]");(e.length===0?[t]:e).forEach(n=>n.addEventListener("click",G))}function T(t){Z(t)?h(f("Purchase",t),t):(p?p.observe(t):h(f("Impression",t),t),K(t))}function b(t){const e=t.querySelectorAll(y);for(let s=0;s<e.length;s++){const n=e[s];n instanceof HTMLElement&&T(n)}}function Z(t){return t.dataset.tsAction==="purchase"}function W(t){for(const e of t)if(e.type==="childList"){const s=new Set;for(let n=0;n<e.addedNodes.length;n++){const o=e.addedNodes[n];if((o==null?void 0:o.nodeType)===Node.ELEMENT_NODE){const r=o.parentElement;r&&!s.has(r)&&s.add(r)}for(const r of s)b(r)}}else if(e.type==="attributes"){if(!(e.target instanceof HTMLElement))continue;T(e.target)}}function k(){var s,n;if((s=window.TS)!=null&&s.loaded)return;if(window.TS.loaded=!0,!((n=window.TS)!=null&&n.token)){console.error("Missing TS token");return}b(document);const t=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;new t(W).observe(document,{attributes:!0,childList:!0,subtree:!0,attributeFilter:["data-ts-product","data-ts-action","data-ts-items","data-ts-resolved-bid"]})}/complete|interactive|loaded/.test(document.readyState)?k():window.addEventListener("DOMContentLoaded",k)}); | ||
| (function(u){typeof define=="function"&&define.amd?define(u):u()})(function(){"use strict";class u{constructor(){this._data=[]}get(){return this._data}set(e){this._data=e}}class _{constructor(e){this._key=e,this._storage=window.localStorage}get(){const e=this._storage.getItem(this._key);return e?JSON.parse(e):[]}set(e){this._storage.setItem(this._key,JSON.stringify(e))}}class M{constructor(e){this._key=e,this._storage=window.sessionStorage,this._bid=void 0}get(){try{return this._storage.getItem(this._key)??void 0}catch{return this._bid}}set(e){this._bid=e;try{this._storage.setItem(this._key,e)}catch{}}}const P="ts-t",v="ts-q",N=250,A=3,R=25,C=250,m=9,L=0;function U(t,e){return e>0?t+(Math.random()+Math.pow(2,e))*1e3:0}function q(){var e;const t=new _(P);try{const s="3";if(t.set([{x:s}]),((e=t.get()[0])==null?void 0:e.x)===s)return new _(v)}catch{}return new u}class x{constructor(e){this._store=q(),this._processing=new Set,this._scheduled=!1,this._processor=e}append(e,s){let o=this._store.get();o.push({e,r:0,p:s!=null&&s.highPriority?m:L}),o=o.slice(-N),this._setEntries(o)}async _processNow(e){if(!e.length)return;const s=[];for(let i=e.length-1;i>=0&&s.length<R;i--){const c=e[i],h=c==null?void 0:c.e;h&&!this._processing.has(h.id)&&U(h.t,c.r)<=Date.now()&&(s.push(h),this._processing.add(h.id))}if(!s.length){this._scheduleProcessing();return}let o={done:new Set,retry:new Set};try{o=await this._processor(s)}catch{for(const c of s)o.done.add(c.id)}const n=[];for(const i of this._processing)s.find(c=>c.id===i)||n.push(i);this._processing=new Set(n);const r=this._store.get(),d=[];for(const i of r)o.done.has(i.e.id)||(o.retry.has(i.e.id)?i.r<A&&(i.r+=1,d.push(i)):d.push(i));this._setEntries(d)}_setEntries(e){this._store.set(e),e.length&&(e.some(s=>s.p===m)||this._store instanceof u?this._processNow(e):this._scheduleProcessing())}_scheduleProcessing(){this._scheduled||(this._scheduled=!0,setTimeout(()=>{this._scheduled=!1,this._processNow(this._store.get())},C))}}const H="2.2.0";async function B(t,e){try{const s=(e.url||"https://api.topsort.com")+"/v2/events",o=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json","X-UA":`ts.js/${H}`,Authorization:"Bearer "+e.token},body:JSON.stringify(t),keepalive:!0});return{ok:o.ok,retry:o.status===429||o.status>=500}}catch{return{ok:!1,retry:!0}}}const S=2500,D=.5;let a=new Set;const I=new M("ts-b");function E(){var t,e;return((e=(t=window.URL).createObjectURL)==null?void 0:e.call(t,new Blob).split("/").pop())||Math.random()+""}let l;function g(){if(l)return l;const t=j();if(t)return l=t,t;const e=E();return y(e),e}function y(t){const e=window.TS.cookieName||"tsuid";l=t,document.cookie=e+"="+t+";max-age=31536000"}function X(){return l=void 0,document.cookie="tsuid=",g()}window.TS.setUserId=y,window.TS.getUserId=g,window.TS.resetUserId=X;function j(){var s;const t=window.TS.cookieName||"tsuid";return(s=new RegExp("(^|;)\\s*"+t+"\\s*=\\s*([^;]+)").exec(document.cookie))==null?void 0:s.pop()}function z(t){const e=t.type,s={path:t.page};let o;t.product&&(o={type:"product",id:t.product});let n;t.additionalProduct&&(n={type:"product",id:t.additionalProduct});const r=new Date(t.t).toISOString();switch(e){case"Click":return{clicks:[{resolvedBidId:t.bid,entity:o,additionalAttribution:n,placement:s,occurredAt:r,opaqueUserId:t.uid,id:t.id}]};case"Impression":return{impressions:[{resolvedBidId:t.bid,entity:o,additionalAttribution:n,placement:s,occurredAt:r,opaqueUserId:t.uid,id:t.id}]};case"Purchase":return{purchases:[{occurredAt:r,opaqueUserId:t.uid,items:(t.items||[]).map(d=>({productId:d.product,quantity:d.quantity,unitPrice:d.price})),id:t.id}]}}}async function J(t){const e={done:new Set,retry:new Set},s=[];for(const o of t)s.push(B(z(o),window.TS).then(n=>{(n.retry?e.retry:e.done).add(o.id)}).catch(()=>{e.done.add(o.id)}));return await Promise.all(s),e}const Y=new x(J);function f(t,e){const s=G(t);if(a.has(s))return;if(a.add(s),a.size>S){const n=a.values();for(let r=0;r<a.size-S;--r)n.next();a=new Set(n)}Y.append(t);const o=new CustomEvent("topsort",{bubbles:!0,detail:t});e.dispatchEvent(o)}function G(t){return[t.page,t.type,t.product??t.additionalProduct,t.bid].join("-")}function K(){const t=window.location,e=t.hash;return e[1]==="/"?e:t.pathname}function p(t,e){let s=e.dataset.tsProduct,o=e.dataset.tsResolvedBid,n;o=="inherit"&&s&&(t=="Click"||t=="Impression")&&(o=I.get(),n=s,s=void 0);const r={type:t,product:s,additionalProduct:n,bid:o,t:Date.now(),page:K(),id:E(),uid:g()};return t==="Purchase"&&(r.items=JSON.parse(e.dataset.tsItems||"[]")),r}function Z(t){if(!(t.currentTarget instanceof HTMLElement))return;const e=t.currentTarget.closest(b);if(e&&e instanceof HTMLElement){const s=p("Click",e);f(s,e),s.bid&&I.set(s.bid)}}const w=window.IntersectionObserver?new IntersectionObserver(t=>{for(const e of t)if(e.isIntersecting){const s=e.target;s instanceof HTMLElement&&(f(p("Impression",s),s),w&&w.unobserve(s))}},{threshold:D}):void 0,b="[data-ts-product],[data-ts-action],[data-ts-items],[data-ts-resolved-bid]";function W(t){const e=t.querySelectorAll("[data-ts-clickable]");(e.length===0?[t]:e).forEach(o=>o.addEventListener("click",Z))}function T(t){F(t)?f(p("Purchase",t),t):(w?w.observe(t):f(p("Impression",t),t),W(t))}function k(t){const e=t.querySelectorAll(b);for(let s=0;s<e.length;s++){const o=e[s];o instanceof HTMLElement&&T(o)}}function F(t){return t.dataset.tsAction==="purchase"}function Q(t){for(const e of t)if(e.type==="childList"){const s=new Set;for(let o=0;o<e.addedNodes.length;o++){const n=e.addedNodes[o];if((n==null?void 0:n.nodeType)===Node.ELEMENT_NODE){const r=n.parentElement;r&&!s.has(r)&&s.add(r)}for(const r of s)k(r)}}else if(e.type==="attributes"){if(!(e.target instanceof HTMLElement))continue;T(e.target)}}function O(){var s,o;if((s=window.TS)!=null&&s.loaded)return;if(window.TS.loaded=!0,!((o=window.TS)!=null&&o.token)){console.error("Missing TS token");return}k(document);const t=window.MutationObserver||window.WebKitMutationObserver||window.MozMutationObserver;new t(Q).observe(document,{attributes:!0,childList:!0,subtree:!0,attributeFilter:["data-ts-product","data-ts-action","data-ts-items","data-ts-resolved-bid"]})}/complete|interactive|loaded/.test(document.readyState)?O():window.addEventListener("DOMContentLoaded",O)}); |
+123
-85
@@ -24,13 +24,32 @@ class I { | ||
| } | ||
| const O = "ts-t", M = "ts-q", N = 250, v = 3, P = 25, A = 250, m = 9, R = 0; | ||
| function L(t, e) { | ||
| class M { | ||
| constructor(e) { | ||
| this._key = e, this._storage = window.sessionStorage, this._bid = void 0; | ||
| } | ||
| get() { | ||
| try { | ||
| return this._storage.getItem(this._key) ?? void 0; | ||
| } catch { | ||
| return this._bid; | ||
| } | ||
| } | ||
| set(e) { | ||
| this._bid = e; | ||
| try { | ||
| this._storage.setItem(this._key, e); | ||
| } catch { | ||
| } | ||
| } | ||
| } | ||
| const P = "ts-t", v = "ts-q", N = 250, A = 3, R = 25, C = 250, _ = 9, L = 0; | ||
| function U(t, e) { | ||
| return e > 0 ? t + (Math.random() + Math.pow(2, e)) * 1e3 : 0; | ||
| } | ||
| function U() { | ||
| function q() { | ||
| var e; | ||
| const t = new g(O); | ||
| const t = new g(P); | ||
| try { | ||
| const s = "3"; | ||
| if (t.set([{ x: s }]), ((e = t.get()[0]) == null ? void 0 : e.x) === s) | ||
| return new g(M); | ||
| return new g(v); | ||
| } catch { | ||
@@ -40,5 +59,5 @@ } | ||
| } | ||
| class C { | ||
| class x { | ||
| constructor(e) { | ||
| this._store = U(), this._processing = /* @__PURE__ */ new Set(), this._scheduled = !1, this._processor = e; | ||
| this._store = q(), this._processing = /* @__PURE__ */ new Set(), this._scheduled = !1, this._processor = e; | ||
| } | ||
@@ -50,3 +69,3 @@ append(e, s) { | ||
| r: 0, | ||
| p: s != null && s.highPriority ? m : R | ||
| p: s != null && s.highPriority ? _ : L | ||
| }), o = o.slice(-N), this._setEntries(o); | ||
@@ -58,5 +77,5 @@ } | ||
| const s = []; | ||
| for (let i = e.length - 1; i >= 0 && s.length < P; i--) { | ||
| const c = e[i], d = c == null ? void 0 : c.e; | ||
| d && !this._processing.has(d.id) && L(d.t, c.r) <= Date.now() && (s.push(d), this._processing.add(d.id)); | ||
| for (let i = e.length - 1; i >= 0 && s.length < R; i--) { | ||
| const c = e[i], u = c == null ? void 0 : c.e; | ||
| u && !this._processing.has(u.id) && U(u.t, c.r) <= Date.now() && (s.push(u), this._processing.add(u.id)); | ||
| } | ||
@@ -74,13 +93,13 @@ if (!s.length) { | ||
| } | ||
| const n = []; | ||
| const r = []; | ||
| for (const i of this._processing) | ||
| s.find((c) => c.id === i) || n.push(i); | ||
| this._processing = new Set(n); | ||
| const r = this._store.get(), p = []; | ||
| for (const i of r) | ||
| o.done.has(i.e.id) || (o.retry.has(i.e.id) ? i.r < v && (i.r += 1, p.push(i)) : p.push(i)); | ||
| this._setEntries(p); | ||
| s.find((c) => c.id === i) || r.push(i); | ||
| this._processing = new Set(r); | ||
| const n = this._store.get(), d = []; | ||
| for (const i of n) | ||
| o.done.has(i.e.id) || (o.retry.has(i.e.id) ? i.r < A && (i.r += 1, d.push(i)) : d.push(i)); | ||
| this._setEntries(d); | ||
| } | ||
| _setEntries(e) { | ||
| this._store.set(e), e.length && (e.some((s) => s.p === m) || this._store instanceof I ? this._processNow(e) : this._scheduleProcessing()); | ||
| this._store.set(e), e.length && (e.some((s) => s.p === _) || this._store instanceof I ? this._processNow(e) : this._scheduleProcessing()); | ||
| } | ||
@@ -90,7 +109,7 @@ _scheduleProcessing() { | ||
| this._scheduled = !1, this._processNow(this._store.get()); | ||
| }, A)); | ||
| }, C)); | ||
| } | ||
| } | ||
| const q = "2.1.0"; | ||
| async function x(t, e) { | ||
| const H = "2.2.0"; | ||
| async function B(t, e) { | ||
| try { | ||
@@ -103,3 +122,3 @@ const s = (e.url || "https://api.topsort.com") + "/v2/events", o = await fetch(s, { | ||
| // https://bugs.chromium.org/p/chromium/issues/detail?id=571722 | ||
| "X-UA": `ts.js/${q}`, | ||
| "X-UA": `ts.js/${H}`, | ||
| Authorization: "Bearer " + e.token | ||
@@ -116,29 +135,30 @@ }, | ||
| } | ||
| const _ = 2500, H = 0.5; | ||
| const m = 2500, D = 0.5; | ||
| let a = /* @__PURE__ */ new Set(); | ||
| function E() { | ||
| const E = new M("ts-b"); | ||
| function y() { | ||
| var t, e; | ||
| return ((e = (t = window.URL).createObjectURL) == null ? void 0 : e.call(t, new Blob()).split("/").pop()) || Math.random() + ""; | ||
| } | ||
| let u; | ||
| let l; | ||
| function w() { | ||
| if (u) | ||
| return u; | ||
| const t = B(); | ||
| if (l) | ||
| return l; | ||
| const t = j(); | ||
| if (t) | ||
| return u = t, t; | ||
| const e = E(); | ||
| return y(e), e; | ||
| return l = t, t; | ||
| const e = y(); | ||
| return b(e), e; | ||
| } | ||
| function y(t) { | ||
| function b(t) { | ||
| const e = window.TS.cookieName || "tsuid"; | ||
| u = t, document.cookie = e + "=" + t + ";max-age=31536000"; | ||
| l = t, document.cookie = e + "=" + t + ";max-age=31536000"; | ||
| } | ||
| function D() { | ||
| return u = void 0, document.cookie = "tsuid=", w(); | ||
| function X() { | ||
| return l = void 0, document.cookie = "tsuid=", w(); | ||
| } | ||
| window.TS.setUserId = y; | ||
| window.TS.setUserId = b; | ||
| window.TS.getUserId = w; | ||
| window.TS.resetUserId = D; | ||
| function B() { | ||
| window.TS.resetUserId = X; | ||
| function j() { | ||
| var s; | ||
@@ -148,3 +168,3 @@ const t = window.TS.cookieName || "tsuid"; | ||
| } | ||
| function X(t) { | ||
| function z(t) { | ||
| const e = t.type, s = { | ||
@@ -158,2 +178,7 @@ path: t.page | ||
| }); | ||
| let r; | ||
| t.additionalProduct && (r = { | ||
| type: "product", | ||
| id: t.additionalProduct | ||
| }); | ||
| const n = new Date(t.t).toISOString(); | ||
@@ -167,2 +192,3 @@ switch (e) { | ||
| entity: o, | ||
| additionalAttribution: r, | ||
| placement: s, | ||
@@ -181,2 +207,3 @@ occurredAt: n, | ||
| entity: o, | ||
| additionalAttribution: r, | ||
| placement: s, | ||
@@ -195,6 +222,6 @@ occurredAt: n, | ||
| opaqueUserId: t.uid, | ||
| items: (t.items || []).map((r) => ({ | ||
| productId: r.product, | ||
| quantity: r.quantity, | ||
| unitPrice: r.price | ||
| items: (t.items || []).map((d) => ({ | ||
| productId: d.product, | ||
| quantity: d.quantity, | ||
| unitPrice: d.price | ||
| })), | ||
@@ -207,3 +234,3 @@ id: t.id | ||
| } | ||
| async function j(t) { | ||
| async function J(t) { | ||
| const e = { | ||
@@ -215,4 +242,4 @@ done: /* @__PURE__ */ new Set(), | ||
| s.push( | ||
| x(X(o), window.TS).then((n) => { | ||
| (n.retry ? e.retry : e.done).add(o.id); | ||
| B(z(o), window.TS).then((r) => { | ||
| (r.retry ? e.retry : e.done).add(o.id); | ||
| }).catch(() => { | ||
@@ -224,32 +251,40 @@ e.done.add(o.id); | ||
| } | ||
| const z = new C(j); | ||
| function l(t, e) { | ||
| const s = J(t); | ||
| const Y = new x(J); | ||
| function h(t, e) { | ||
| const s = G(t); | ||
| if (a.has(s)) | ||
| return; | ||
| if (a.add(s), a.size > _) { | ||
| const n = a.values(); | ||
| for (let r = 0; r < a.size - _; --r) | ||
| n.next(); | ||
| a = new Set(n); | ||
| if (a.add(s), a.size > m) { | ||
| const r = a.values(); | ||
| for (let n = 0; n < a.size - m; --n) | ||
| r.next(); | ||
| a = new Set(r); | ||
| } | ||
| z.append(t); | ||
| Y.append(t); | ||
| const o = new CustomEvent("topsort", { bubbles: !0, detail: t }); | ||
| e.dispatchEvent(o); | ||
| } | ||
| function J(t) { | ||
| return [t.page, t.type, t.product, t.bid].join("-"); | ||
| function G(t) { | ||
| return [ | ||
| t.page, | ||
| t.type, | ||
| t.product ?? t.additionalProduct, | ||
| t.bid | ||
| ].join("-"); | ||
| } | ||
| function Y() { | ||
| function K() { | ||
| const t = window.location, e = t.hash; | ||
| return e[1] === "/" ? e : t.pathname; | ||
| } | ||
| function h(t, e) { | ||
| const s = e.dataset.tsProduct, o = e.dataset.tsResolvedBid, n = { | ||
| function f(t, e) { | ||
| let s = e.dataset.tsProduct, o = e.dataset.tsResolvedBid, r; | ||
| o == "inherit" && s && (t == "Click" || t == "Impression") && (o = E.get(), r = s, s = void 0); | ||
| const n = { | ||
| type: t, | ||
| product: s, | ||
| additionalProduct: r, | ||
| bid: o, | ||
| t: Date.now(), | ||
| page: Y(), | ||
| id: E(), | ||
| page: K(), | ||
| id: y(), | ||
| uid: w() | ||
@@ -259,9 +294,12 @@ }; | ||
| } | ||
| function G(t) { | ||
| function Z(t) { | ||
| if (!(t.currentTarget instanceof HTMLElement)) | ||
| return; | ||
| const e = t.currentTarget.closest(T); | ||
| e && e instanceof HTMLElement && l(h("Click", e), e); | ||
| if (e && e instanceof HTMLElement) { | ||
| const s = f("Click", e); | ||
| h(s, e), s.bid && E.set(s.bid); | ||
| } | ||
| } | ||
| const f = window.IntersectionObserver ? new IntersectionObserver( | ||
| const p = window.IntersectionObserver ? new IntersectionObserver( | ||
| (t) => { | ||
@@ -271,27 +309,27 @@ for (const e of t) | ||
| const s = e.target; | ||
| s instanceof HTMLElement && (l(h("Impression", s), s), f && f.unobserve(s)); | ||
| s instanceof HTMLElement && (h(f("Impression", s), s), p && p.unobserve(s)); | ||
| } | ||
| }, | ||
| { | ||
| threshold: H | ||
| threshold: D | ||
| } | ||
| ) : void 0, T = "[data-ts-product],[data-ts-action],[data-ts-items],[data-ts-resolved-bid]"; | ||
| function K(t) { | ||
| function W(t) { | ||
| const e = t.querySelectorAll("[data-ts-clickable]"); | ||
| (e.length === 0 ? [t] : e).forEach((o) => o.addEventListener("click", G)); | ||
| (e.length === 0 ? [t] : e).forEach((o) => o.addEventListener("click", Z)); | ||
| } | ||
| function b(t) { | ||
| Z(t) ? l(h("Purchase", t), t) : (f ? f.observe(t) : l(h("Impression", t), t), K(t)); | ||
| function k(t) { | ||
| F(t) ? h(f("Purchase", t), t) : (p ? p.observe(t) : h(f("Impression", t), t), W(t)); | ||
| } | ||
| function k(t) { | ||
| function O(t) { | ||
| const e = t.querySelectorAll(T); | ||
| for (let s = 0; s < e.length; s++) { | ||
| const o = e[s]; | ||
| o instanceof HTMLElement && b(o); | ||
| o instanceof HTMLElement && k(o); | ||
| } | ||
| } | ||
| function Z(t) { | ||
| function F(t) { | ||
| return t.dataset.tsAction === "purchase"; | ||
| } | ||
| function W(t) { | ||
| function Q(t) { | ||
| for (const e of t) | ||
@@ -301,9 +339,9 @@ if (e.type === "childList") { | ||
| for (let o = 0; o < e.addedNodes.length; o++) { | ||
| const n = e.addedNodes[o]; | ||
| if ((n == null ? void 0 : n.nodeType) === Node.ELEMENT_NODE) { | ||
| const r = n.parentElement; | ||
| r && !s.has(r) && s.add(r); | ||
| const r = e.addedNodes[o]; | ||
| if ((r == null ? void 0 : r.nodeType) === Node.ELEMENT_NODE) { | ||
| const n = r.parentElement; | ||
| n && !s.has(n) && s.add(n); | ||
| } | ||
| for (const r of s) | ||
| k(r); | ||
| for (const n of s) | ||
| O(n); | ||
| } | ||
@@ -313,3 +351,3 @@ } else if (e.type === "attributes") { | ||
| continue; | ||
| b(e.target); | ||
| k(e.target); | ||
| } | ||
@@ -325,5 +363,5 @@ } | ||
| } | ||
| k(document); | ||
| O(document); | ||
| const t = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; | ||
| new t(W).observe(document, { | ||
| new t(Q).observe(document, { | ||
| attributes: !0, | ||
@@ -330,0 +368,0 @@ childList: !0, |
+8
-8
| { | ||
| "name": "@topsort/analytics.js", | ||
| "version": "2.1.0", | ||
| "version": "2.2.0", | ||
| "description": "JS library to automatically report events to Topsort's Analytics", | ||
@@ -41,12 +41,12 @@ "main": "dist/ts.js", | ||
| "@types/express": "^4.17.17", | ||
| "@types/node": "^20.5.7", | ||
| "@types/node": "^20.8.10", | ||
| "@types/react": "^18.2.21", | ||
| "@types/react-dom": "^18.2.7", | ||
| "@types/react-dom": "^18.2.8", | ||
| "@typescript-eslint/eslint-plugin": "^6.5.0", | ||
| "@typescript-eslint/parser": "^6.5.0", | ||
| "@typescript-eslint/parser": "^6.9.1", | ||
| "@vitest/coverage-v8": "^0.34.3", | ||
| "eslint": "^8.48.0", | ||
| "eslint": "^8.52.0", | ||
| "eslint-config-prettier": "^9.0.0", | ||
| "eslint-plugin-prettier": "^5.0.0", | ||
| "eslint-plugin-vitest": "^0.2.8", | ||
| "eslint-plugin-vitest": "^0.3.1", | ||
| "express": "^4.18.2", | ||
@@ -58,6 +58,6 @@ "jsdom": "^22.1.0", | ||
| "react-dom": "^18.2.0", | ||
| "react-router-dom": "^6.15.0", | ||
| "react-router-dom": "^6.16.0", | ||
| "tslib": "^2.6.2", | ||
| "typescript": "^5.2.2", | ||
| "vite": "^4.4.9", | ||
| "vite": "^4.5.0", | ||
| "vite-plugin-dts": "^3.5.3", | ||
@@ -64,0 +64,0 @@ "vitest": "^0.33.0" |
+22
-10
@@ -31,3 +31,3 @@  | ||
| </script> | ||
| <script src="https://unpkg.com/@topsort/analytics.js@2.0.0/dist/ts.js"></script> | ||
| <script src="https://unpkg.com/@topsort/analytics.js@2.2.0/dist/ts.js"></script> | ||
| ``` | ||
@@ -43,14 +43,14 @@ | ||
| Pass said values to your html: | ||
| Add the following markup to promoted products: | ||
| ```html | ||
| <div | ||
| class="product" | ||
| data-ts-product="<productId>" | ||
| data-ts-resolved-bid="<resolvedBidId>" | ||
| > | ||
| ... | ||
| </div> | ||
| <div class="product" data-ts-resolved-bid="<resolvedBidId>">...</div> | ||
| ``` | ||
| and the following for organic products (which is optional) | ||
| ```html | ||
| <div class="product" data-ts-product="<productId>">...</div> | ||
| ``` | ||
| Additionally, in case not all the container is clickable (i.e., does not produce an action or does not take you to the product page) or parts of it lead you to a non-related product page, make sure to use the `data-ts-clickable` attribute to indicate what portions of the product should count as a conversion. | ||
@@ -68,3 +68,3 @@ | ||
| Finally, adding further information to purchases can be made by passing the `ts-data-items` JSON array: | ||
| Adding further information to purchases can be made by passing the `ts-data-items` JSON array: | ||
@@ -80,2 +80,14 @@ ```html | ||
| Finally, in case you are using banners and want to have further control on the attributable products you need to add the following markup in the banner's destination page. | ||
| ```html | ||
| <div | ||
| class="product" | ||
| data-ts-product="<productId>" | ||
| data-ts-resolved-bid="inherit" | ||
| > | ||
| ... | ||
| </div> | ||
| ``` | ||
| # E2E tests | ||
@@ -82,0 +94,0 @@ |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
24876
9.23%493
11.29%94
14.63%2
-50%