@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.
- package/dist/webority-analytics-site.global.js +1 -1
- package/package.json +1 -1
- package/src/consent.js +50 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
var WeborityAnalytics=(()=>{var m=Object.defineProperty;var
|
|
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&<(),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
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
|
-
|
|
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
|
|
163
|
+
const entries = (document.cookie || "")
|
|
157
164
|
.split(";")
|
|
158
165
|
.map((part) => part.trim())
|
|
159
|
-
.
|
|
160
|
-
|
|
161
|
-
|
|
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(
|
|
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
|
-
|
|
184
|
-
const
|
|
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 =
|
|
227
|
+
document.cookie = text;
|
|
188
228
|
}
|
|
189
229
|
|
|
190
230
|
export function resetConsentForTests() {
|