@webority/analytics 0.5.1 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- var WeborityAnalytics=(()=>{var m=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var j=Object.prototype.hasOwnProperty;var G=(t,e)=>{for(var n in e)m(t,n,{get:e[n],enumerable:!0})},K=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of $(e))!j.call(t,r)&&r!==n&&m(t,r,{get:()=>e[r],enumerable:!(o=M(e,r))||o.enumerable});return t};var P=t=>K(m({},"__esModule",{value:!0}),t);var ct={};G(ct,{CONSENT_CHANGE_EVENT:()=>y,CONSENT_COOKIE_NAME:()=>u,captureAttribution:()=>x,getAttribution:()=>R,getConsent:()=>a,initConsent:()=>N,loadTags:()=>q,onConsentChange:()=>c,requiresOptIn:()=>b,saveConsent:()=>L});var p=Object.freeze(["AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","IS","LI","NO","GB","CH"]);function b(t){let e=typeof t=="string"?t.trim().toUpperCase():"";return e.length!==2||e==="XX"||e==="T1"?!0:p.includes(e)}var u="webority_cookie_consent",y="webority-consent-change",H=365,i={initialized:!1,requiresOptIn:!0,cookieDomain:null,saved:null},g=new Set;function N(t){if(typeof t?.requiresOptIn!="boolean")throw new Error("@webority/analytics: initConsent needs requiresOptIn (true or false), decided from the visitor's country.");if(t.cookieDomain!==void 0&&(typeof t.cookieDomain!="string"||!t.cookieDomain.trim()))throw new Error('@webority/analytics: initConsent cookieDomain must be a domain such as ".example.com", or left out.');i.initialized=!0,i.requiresOptIn=t.requiresOptIn,i.cookieDomain=t.cookieDomain?.trim()??null,i.saved=X(),B(),i.saved&&v(i.saved)}function l(){return i.initialized}function a(){k("getConsent");let t=i.saved;if(t)return{essential:!0,analytics:t.analytics,functional:t.functional,marketing:t.marketing,decided:!0};let e=!i.requiresOptIn;return{essential:!0,analytics:e,functional:e,marketing:e,decided:!1}}function L(t){k("saveConsent");let e={essential:!0,analytics:t?.analytics===!0,functional:t?.functional===!0,marketing:t?.marketing===!0,timestamp:new Date().toISOString()};J(e),i.saved=e,v(e),Y(a())}function c(t){return g.add(t),()=>g.delete(t)}function Y(t){for(let e of g)try{e(t)}catch(n){queueMicrotask(()=>{throw n})}typeof window?.dispatchEvent=="function"&&typeof CustomEvent=="function"&&window.dispatchEvent(new CustomEvent(y,{detail:t}))}function k(t){if(!i.initialized)throw new Error(`@webority/analytics: call initConsent before ${t}.`)}function w(){window.dataLayer=window.dataLayer||[],window.dataLayer.push(arguments)}function B(){w("consent","default",{ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",functionality_storage:"denied",personalization_storage:"denied",security_storage:"granted",wait_for_update:500,region:[...p]}),w("consent","default",{ad_storage:"granted",ad_user_data:"granted",ad_personalization:"granted",analytics_storage:"granted",functionality_storage:"granted",personalization_storage:"granted",security_storage:"granted"})}function v(t){let e=n=>n?"granted":"denied";w("consent","update",{analytics_storage:e(t.analytics),functionality_storage:e(t.functional),personalization_storage:e(t.functional),ad_storage:e(t.marketing),ad_user_data:e(t.marketing),ad_personalization:e(t.marketing)})}function X(){let t=`${u}=`,e=(document.cookie||"").split(";").map(n=>n.trim()).find(n=>n.startsWith(t));if(!e)return null;try{let n=JSON.parse(decodeURIComponent(e.slice(t.length)));return!n||typeof n!="object"?null:{essential:!0,analytics:n.analytics===!0,functional:n.functional===!0,marketing:n.marketing===!0,timestamp:n.timestamp??null}}catch{return null}}function J(t){let e=new Date(Date.now()+H*24*60*60*1e3).toUTCString(),n=i.cookieDomain?`;domain=${i.cookieDomain}`:"",o=window.location?.protocol==="https:"?";Secure":"";document.cookie=`${u}=${encodeURIComponent(JSON.stringify(t))};expires=${e};path=/${n};SameSite=Lax${o}`}var f="webority_attribution",V=2160*60*60*1e3,Q=200,C=500,W=Object.freeze({utm_source:"utmSource",utm_medium:"utmMedium",utm_campaign:"utmCampaign",utm_content:"utmContent",utm_term:"utmTerm",gclid:"gclid",gbraid:"gbraid",wbraid:"wbraid",fbclid:"fbclid",msclkid:"msclkid",li_fat_id:"liFatId"}),A=!1;function x(){U("captureAttribution"),et();let t=Z();if(!t)return;let e=I(_());z(_(),{firstTouch:e?.firstTouch??t,lastTouch:t})}function R(){return U("getAttribution"),I(_())}function Z(){let t=new URLSearchParams(window.location.search),e={};for(let[o,r]of Object.entries(W)){let O=d(t.get(o),Q);O&&(e[r]=O)}let n=d(t.get("referrer"),C)||tt();return n&&(e.referrer=n),Object.keys(e).length===0?null:(e.landingPage=d(window.location.pathname,C),e.capturedDateTimeUtc=new Date().toISOString(),e)}function tt(){let t=document.referrer;if(!t)return"";try{return new URL(t).hostname===window.location.hostname?"":d(t,C)}catch{return""}}function et(){A||(A=!0,c(t=>{let e=t.marketing?T():h(),n=t.marketing?h():T(),o=I(e);nt(e),o&&z(n,o)}))}function _(){return a().marketing?h():T()}function h(){try{return window.localStorage}catch{return null}}function T(){try{return window.sessionStorage}catch{return null}}function I(t){try{let e=t?.getItem(f);if(!e)return null;let n=JSON.parse(e),o=D(n?.firstTouch),r=D(n?.lastTouch);return!o&&!r?(t.removeItem(f),null):{firstTouch:o??r,lastTouch:r??o}}catch{return null}}function z(t,e){try{t?.setItem(f,JSON.stringify(e))}catch{}}function nt(t){try{t?.removeItem(f)}catch{}}function D(t){if(!t||typeof t!="object")return null;let e=Date.parse(t.capturedDateTimeUtc);return Number.isFinite(e)&&Date.now()-e<=V?t:null}function d(t,e){let n=String(t??"").trim();return n?n.slice(0,e):""}function U(t){if(!l())throw new Error(`@webority/analytics: call initConsent before ${t}.`)}var ot=["scroll","mousemove","touchstart","keydown","pointerdown"],F=1500,rt=3e3,it=100,s={loaded:!1,clarityId:null,clarityLoaded:!1};function q(t={}){if(!l())throw new Error("@webority/analytics: call initConsent before loadTags.");if(s.loaded)return;s.loaded=!0;let{gtmId:e,clarityId:n,ahrefsKey:o}=t;o&&S("https://analytics.ahrefs.com/analytics.js",{"data-key":o}),e&&at(()=>{window.dataLayer=window.dataLayer||[],window.dataLayer.push({"gtm.start":Date.now(),event:"gtm.js"}),S(`https://www.googletagmanager.com/gtm.js?id=${encodeURIComponent(e)}`)}),n&&(s.clarityId=n,a().analytics&&st(),c(r=>{r.analytics&&E()}))}function at(t){let e=!1,n=()=>{e||(e=!0,t())};for(let o of ot)window.addEventListener(o,n,{once:!0,passive:!0});document.readyState==="complete"?setTimeout(n,F):window.addEventListener("load",()=>setTimeout(n,F),{once:!0})}function st(){let t=()=>{window.scrollY>it&&(window.removeEventListener("scroll",t),E())};window.addEventListener("scroll",t,{passive:!0}),setTimeout(E,rt)}function E(){s.clarityLoaded||!s.clarityId||(s.clarityLoaded=!0,window.clarity=window.clarity||function(){window.clarity.q=window.clarity.q||[],window.clarity.q.push(arguments)},S(`https://www.clarity.ms/tag/${encodeURIComponent(s.clarityId)}`,{crossorigin:"anonymous"}))}function S(t,e={}){let n=document.createElement("script");n.async=!0,n.src=t;for(let[o,r]of Object.entries(e))n.setAttribute(o,r);document.head.appendChild(n)}return P(ct);})();
1
+ var WeborityAnalytics=(()=>{var m=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var K=Object.prototype.hasOwnProperty;var P=(t,e)=>{for(var n in e)m(t,n,{get:e[n],enumerable:!0})},H=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of G(e))!K.call(t,r)&&r!==n&&m(t,r,{get:()=>e[r],enumerable:!(o=j(e,r))||o.enumerable});return t};var B=t=>H(m({},"__esModule",{value:!0}),t);var dt={};P(dt,{CONSENT_CHANGE_EVENT:()=>y,CONSENT_COOKIE_NAME:()=>u,captureAttribution:()=>z,getAttribution:()=>U,getConsent:()=>a,initConsent:()=>k,loadTags:()=>M,onConsentChange:()=>c,requiresOptIn:()=>O,saveConsent:()=>L});var p=Object.freeze(["AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","IS","LI","NO","GB","CH"]);function O(t){let e=typeof t=="string"?t.trim().toUpperCase():"";return e.length!==2||e==="XX"||e==="T1"?!0:p.includes(e)}var u="webority_cookie_consent",y="webority-consent-change",Y=365,i={initialized:!1,requiresOptIn:!0,cookieDomain:null,saved:null},g=new Set;function k(t){if(typeof t?.requiresOptIn!="boolean")throw new Error("@webority/analytics: initConsent needs requiresOptIn (true or false), decided from the visitor's country.");if(t.cookieDomain!==void 0&&(typeof t.cookieDomain!="string"||!t.cookieDomain.trim()))throw new Error('@webority/analytics: initConsent cookieDomain must be a domain such as ".example.com", or left out.');i.initialized=!0,i.requiresOptIn=t.requiresOptIn,i.cookieDomain=t.cookieDomain?.trim()??null;let{saved:e,entryCount:n}=V();i.saved=e,i.cookieDomain&&n>1&&e&&x(e),X(),i.saved&&D(i.saved)}function l(){return i.initialized}function a(){A("getConsent");let t=i.saved;if(t)return{essential:!0,analytics:t.analytics,functional:t.functional,marketing:t.marketing,decided:!0};let e=!i.requiresOptIn;return{essential:!0,analytics:e,functional:e,marketing:e,decided:!1}}function L(t){A("saveConsent");let e={essential:!0,analytics:t?.analytics===!0,functional:t?.functional===!0,marketing:t?.marketing===!0,timestamp:new Date().toISOString()};x(e),i.saved=e,D(e),J(a())}function c(t){return g.add(t),()=>g.delete(t)}function J(t){for(let e of g)try{e(t)}catch(n){queueMicrotask(()=>{throw n})}typeof window?.dispatchEvent=="function"&&typeof CustomEvent=="function"&&window.dispatchEvent(new CustomEvent(y,{detail:t}))}function A(t){if(!i.initialized)throw new Error(`@webority/analytics: call initConsent before ${t}.`)}function w(){window.dataLayer=window.dataLayer||[],window.dataLayer.push(arguments)}function X(){w("consent","default",{ad_storage:"denied",ad_user_data:"denied",ad_personalization:"denied",analytics_storage:"denied",functionality_storage:"denied",personalization_storage:"denied",security_storage:"granted",wait_for_update:500,region:[...p]}),w("consent","default",{ad_storage:"granted",ad_user_data:"granted",ad_personalization:"granted",analytics_storage:"granted",functionality_storage:"granted",personalization_storage:"granted",security_storage:"granted"})}function D(t){let e=n=>n?"granted":"denied";w("consent","update",{analytics_storage:e(t.analytics),functionality_storage:e(t.functional),personalization_storage:e(t.functional),ad_storage:e(t.marketing),ad_user_data:e(t.marketing),ad_personalization:e(t.marketing)})}function V(){let t=`${u}=`,e=(document.cookie||"").split(";").map(o=>o.trim()).filter(o=>o.startsWith(t)),n=e.map(o=>Q(o.slice(t.length))).filter(Boolean);return{saved:W(n),entryCount:e.length}}function Q(t){try{let e=JSON.parse(decodeURIComponent(t));return!e||typeof e!="object"?null:{essential:!0,analytics:e.analytics===!0,functional:e.functional===!0,marketing:e.marketing===!0,timestamp:e.timestamp??null}}catch{return null}}function W(t){if(t.length===0)return null;let e=t.map(o=>typeof o.timestamp=="string"?Date.parse(o.timestamp):Number.NaN);if(e.some(Number.isNaN))return t.at(-1);let n=0;for(let o=1;o<t.length;o++)e[o]>=e[n]&&(n=o);return t[n]}function x(t){let e=typeof t.timestamp=="string"?Date.parse(t.timestamp):Number.NaN,n=(Number.isNaN(e)?Date.now():e)+Y*24*60*60*1e3,o=window.location?.protocol==="https:"?";Secure":"";i.cookieDomain&&b(`${u}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;max-age=0;path=/;SameSite=Lax${o}`);let r=i.cookieDomain?`;domain=${i.cookieDomain}`:"";b(`${u}=${encodeURIComponent(JSON.stringify(t))};expires=${new Date(n).toUTCString()};path=/${r};SameSite=Lax${o}`)}function b(t){document.cookie=t}var f="webority_attribution",Z=2160*60*60*1e3,tt=200,C=500,et=Object.freeze({utm_source:"utmSource",utm_medium:"utmMedium",utm_campaign:"utmCampaign",utm_content:"utmContent",utm_term:"utmTerm",gclid:"gclid",gbraid:"gbraid",wbraid:"wbraid",fbclid:"fbclid",msclkid:"msclkid",li_fat_id:"liFatId"}),v=!1;function z(){q("captureAttribution"),rt();let t=nt();if(!t)return;let e=I(_());F(_(),{firstTouch:e?.firstTouch??t,lastTouch:t})}function U(){return q("getAttribution"),I(_())}function nt(){let t=new URLSearchParams(window.location.search),e={};for(let[o,r]of Object.entries(et)){let S=d(t.get(o),tt);S&&(e[r]=S)}let n=d(t.get("referrer"),C)||ot();return n&&(e.referrer=n),Object.keys(e).length===0?null:(e.landingPage=d(window.location.pathname,C),e.capturedDateTimeUtc=new Date().toISOString(),e)}function ot(){let t=document.referrer;if(!t)return"";try{return new URL(t).hostname===window.location.hostname?"":d(t,C)}catch{return""}}function rt(){v||(v=!0,c(t=>{let e=t.marketing?T():h(),n=t.marketing?h():T(),o=I(e);it(e),o&&F(n,o)}))}function _(){return a().marketing?h():T()}function h(){try{return window.localStorage}catch{return null}}function T(){try{return window.sessionStorage}catch{return null}}function I(t){try{let e=t?.getItem(f);if(!e)return null;let n=JSON.parse(e),o=R(n?.firstTouch),r=R(n?.lastTouch);return!o&&!r?(t.removeItem(f),null):{firstTouch:o??r,lastTouch:r??o}}catch{return null}}function F(t,e){try{t?.setItem(f,JSON.stringify(e))}catch{}}function it(t){try{t?.removeItem(f)}catch{}}function R(t){if(!t||typeof t!="object")return null;let e=Date.parse(t.capturedDateTimeUtc);return Number.isFinite(e)&&Date.now()-e<=Z?t:null}function d(t,e){let n=String(t??"").trim();return n?n.slice(0,e):""}function q(t){if(!l())throw new Error(`@webority/analytics: call initConsent before ${t}.`)}var at=["scroll","mousemove","touchstart","keydown","pointerdown"],$=1500,st=3e3,ct=100,s={loaded:!1,clarityId:null,clarityLoaded:!1};function M(t={}){if(!l())throw new Error("@webority/analytics: call initConsent before loadTags.");if(s.loaded)return;s.loaded=!0;let{gtmId:e,clarityId:n,ahrefsKey:o}=t;o&&N("https://analytics.ahrefs.com/analytics.js",{"data-key":o}),e&&ut(()=>{window.dataLayer=window.dataLayer||[],window.dataLayer.push({"gtm.start":Date.now(),event:"gtm.js"}),N(`https://www.googletagmanager.com/gtm.js?id=${encodeURIComponent(e)}`)}),n&&(s.clarityId=n,a().analytics&&lt(),c(r=>{r.analytics&&E()}))}function ut(t){let e=!1,n=()=>{e||(e=!0,t())};for(let o of at)window.addEventListener(o,n,{once:!0,passive:!0});document.readyState==="complete"?setTimeout(n,$):window.addEventListener("load",()=>setTimeout(n,$),{once:!0})}function lt(){let t=()=>{window.scrollY>ct&&(window.removeEventListener("scroll",t),E())};window.addEventListener("scroll",t,{passive:!0}),setTimeout(E,st)}function E(){s.clarityLoaded||!s.clarityId||(s.clarityLoaded=!0,window.clarity=window.clarity||function(){window.clarity.q=window.clarity.q||[],window.clarity.q.push(arguments)},N(`https://www.clarity.ms/tag/${encodeURIComponent(s.clarityId)}`,{crossorigin:"anonymous"}))}function N(t,e={}){let n=document.createElement("script");n.async=!0,n.src=t;for(let[o,r]of Object.entries(e))n.setAttribute(o,r);document.head.appendChild(n)}return B(dt);})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/analytics",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/consent.js CHANGED
@@ -30,7 +30,14 @@ export function initConsent(options) {
30
30
  consentState.initialized = true;
31
31
  consentState.requiresOptIn = options.requiresOptIn;
32
32
  consentState.cookieDomain = options.cookieDomain?.trim() ?? null;
33
- consentState.saved = readConsentCookie();
33
+ const { saved, entryCount } = readConsentCookie();
34
+ consentState.saved = saved;
35
+
36
+ // A host-only cookie from before the domain was set sits beside the shared one, and
37
+ // browsers list the older first. Folding them into one stops an old choice resurfacing.
38
+ if (consentState.cookieDomain && entryCount > 1 && saved) {
39
+ writeConsentCookie(saved);
40
+ }
34
41
 
35
42
  pushConsentDefaults();
36
43
  if (consentState.saved) {
@@ -153,16 +160,17 @@ function pushConsentUpdate(saved) {
153
160
 
154
161
  function readConsentCookie() {
155
162
  const prefix = `${CONSENT_COOKIE_NAME}=`;
156
- const entry = (document.cookie || "")
163
+ const entries = (document.cookie || "")
157
164
  .split(";")
158
165
  .map((part) => part.trim())
159
- .find((part) => part.startsWith(prefix));
160
- if (!entry) {
161
- return null;
162
- }
166
+ .filter((part) => part.startsWith(prefix));
167
+ const choices = entries.map((entry) => parseConsentEntry(entry.slice(prefix.length))).filter(Boolean);
168
+ return { saved: newestChoice(choices), entryCount: entries.length };
169
+ }
163
170
 
171
+ function parseConsentEntry(value) {
164
172
  try {
165
- const parsed = JSON.parse(decodeURIComponent(entry.slice(prefix.length)));
173
+ const parsed = JSON.parse(decodeURIComponent(value));
166
174
  if (!parsed || typeof parsed !== "object") {
167
175
  return null;
168
176
  }
@@ -179,12 +187,44 @@ function readConsentCookie() {
179
187
  }
180
188
  }
181
189
 
190
+ // Without a readable timestamp on every choice, the last one wins: browsers list equal-path
191
+ // cookies oldest first.
192
+ function newestChoice(choices) {
193
+ if (choices.length === 0) {
194
+ return null;
195
+ }
196
+ const times = choices.map((choice) => (typeof choice.timestamp === "string" ? Date.parse(choice.timestamp) : Number.NaN));
197
+ if (times.some(Number.isNaN)) {
198
+ return choices.at(-1);
199
+ }
200
+ let newest = 0;
201
+ for (let index = 1; index < choices.length; index++) {
202
+ if (times[index] >= times[newest]) {
203
+ newest = index;
204
+ }
205
+ }
206
+ return choices[newest];
207
+ }
208
+
182
209
  function writeConsentCookie(saved) {
183
- const expires = new Date(Date.now() + CONSENT_COOKIE_DAYS * 24 * 60 * 60 * 1000).toUTCString();
184
- const domain = consentState.cookieDomain ? `;domain=${consentState.cookieDomain}` : "";
210
+ // The year runs from the choice, so folding an old choice onto the shared domain does not extend it.
211
+ const chosenAt = typeof saved.timestamp === "string" ? Date.parse(saved.timestamp) : Number.NaN;
212
+ const expiresAt = (Number.isNaN(chosenAt) ? Date.now() : chosenAt) + CONSENT_COOKIE_DAYS * 24 * 60 * 60 * 1000;
185
213
  const secure = window.location?.protocol === "https:" ? ";Secure" : "";
214
+ if (consentState.cookieDomain) {
215
+ // Expired before the shared write: a browser that treats the two as one cookie on the
216
+ // apex host then still ends up holding the shared one.
217
+ setCookie(`${CONSENT_COOKIE_NAME}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;max-age=0;path=/;SameSite=Lax${secure}`);
218
+ }
219
+ const domain = consentState.cookieDomain ? `;domain=${consentState.cookieDomain}` : "";
220
+ setCookie(
221
+ `${CONSENT_COOKIE_NAME}=${encodeURIComponent(JSON.stringify(saved))};expires=${new Date(expiresAt).toUTCString()};path=/${domain};SameSite=Lax${secure}`,
222
+ );
223
+ }
224
+
225
+ function setCookie(text) {
186
226
  // biome-ignore lint/suspicious/noDocumentCookie: the Cookie Store API is missing from browsers our visitors use.
187
- document.cookie = `${CONSENT_COOKIE_NAME}=${encodeURIComponent(JSON.stringify(saved))};expires=${expires};path=/${domain};SameSite=Lax${secure}`;
227
+ document.cookie = text;
188
228
  }
189
229
 
190
230
  export function resetConsentForTests() {