@kylelogue/eventfoundry-tracker 0.3.8 → 0.5.0
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/README.md +107 -10
- package/dist/tracker.min.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ Embedded JavaScript tracking script for EventFoundry - enables custom GA4 event
|
|
|
10
10
|
- [Features](#features)
|
|
11
11
|
- [Configuration](#configuration)
|
|
12
12
|
- [Development Mode](#development-mode)
|
|
13
|
+
- [Debugging Events](#debugging-events)
|
|
13
14
|
- [Editor Integration](#editor-integration)
|
|
14
15
|
- [Architecture](#architecture)
|
|
15
16
|
- [Browser Compatibility](#browser-compatibility)
|
|
@@ -19,22 +20,22 @@ Embedded JavaScript tracking script for EventFoundry - enables custom GA4 event
|
|
|
19
20
|
|
|
20
21
|
## Installation
|
|
21
22
|
|
|
22
|
-
### Via
|
|
23
|
+
### Via jsDelivr CDN (Recommended)
|
|
23
24
|
|
|
24
25
|
Add the script to your website's HTML:
|
|
25
26
|
|
|
26
27
|
```html
|
|
27
|
-
<!--
|
|
28
|
-
<script src="https://
|
|
28
|
+
<!-- Pinned to specific version (recommended for production) -->
|
|
29
|
+
<script src="https://cdn.jsdelivr.net/npm/@kylelogue/eventfoundry-tracker@0.4.0/dist/tracker.min.js"
|
|
29
30
|
data-site-key="YOUR_SITE_KEY_HERE"
|
|
30
31
|
async></script>
|
|
31
32
|
```
|
|
32
33
|
|
|
33
|
-
Or
|
|
34
|
+
Or use the latest version (auto-updates):
|
|
34
35
|
|
|
35
36
|
```html
|
|
36
|
-
<!--
|
|
37
|
-
<script src="https://
|
|
37
|
+
<!-- Latest version (auto-updates - use with caution) -->
|
|
38
|
+
<script src="https://cdn.jsdelivr.net/npm/@kylelogue/eventfoundry-tracker@latest/dist/tracker.min.js"
|
|
38
39
|
data-site-key="YOUR_SITE_KEY_HERE"
|
|
39
40
|
async></script>
|
|
40
41
|
```
|
|
@@ -52,7 +53,7 @@ npm install @kylelogue/eventfoundry-tracker
|
|
|
52
53
|
Let EventFoundry automatically inject Google Analytics 4:
|
|
53
54
|
|
|
54
55
|
```html
|
|
55
|
-
<script src="https://
|
|
56
|
+
<script src="https://cdn.jsdelivr.net/npm/@kylelogue/eventfoundry-tracker@0.4.0/dist/tracker.min.js"
|
|
56
57
|
data-site-key="YOUR_SITE_KEY_HERE"
|
|
57
58
|
data-measurement-id="G-XXXXXXXXXX"
|
|
58
59
|
async></script>
|
|
@@ -73,7 +74,7 @@ If you already have GA4 installed, EventFoundry will detect and use it:
|
|
|
73
74
|
</script>
|
|
74
75
|
|
|
75
76
|
<!-- EventFoundry Tracker -->
|
|
76
|
-
<script src="https://
|
|
77
|
+
<script src="https://cdn.jsdelivr.net/npm/@kylelogue/eventfoundry-tracker@0.4.0/dist/tracker.min.js"
|
|
77
78
|
data-site-key="YOUR_SITE_KEY_HERE"
|
|
78
79
|
async></script>
|
|
79
80
|
```
|
|
@@ -155,14 +156,14 @@ You can override the auto-detection:
|
|
|
155
156
|
|
|
156
157
|
```html
|
|
157
158
|
<!-- Force dev mode on production domain (for testing) -->
|
|
158
|
-
<script src="https://
|
|
159
|
+
<script src="https://cdn.jsdelivr.net/npm/@kylelogue/eventfoundry-tracker@0.4.0/dist/tracker.min.js"
|
|
159
160
|
data-site-key="YOUR_SITE_KEY_HERE"
|
|
160
161
|
data-measurement-id="G-XXXXXXXXXX"
|
|
161
162
|
data-dev-mode="true"
|
|
162
163
|
async></script>
|
|
163
164
|
|
|
164
165
|
<!-- Force production mode on localhost (to test real GA4 events) -->
|
|
165
|
-
<script src="https://
|
|
166
|
+
<script src="https://cdn.jsdelivr.net/npm/@kylelogue/eventfoundry-tracker@0.4.0/dist/tracker.min.js"
|
|
166
167
|
data-site-key="YOUR_SITE_KEY_HERE"
|
|
167
168
|
data-measurement-id="G-XXXXXXXXXX"
|
|
168
169
|
data-dev-mode="false"
|
|
@@ -177,6 +178,102 @@ When development mode is active:
|
|
|
177
178
|
- A console message indicates dev mode is active
|
|
178
179
|
- All tracking logic still runs (useful for testing selectors and event configuration)
|
|
179
180
|
|
|
181
|
+
## Debugging Events
|
|
182
|
+
|
|
183
|
+
Development mode provides enhanced logging to help troubleshoot event tracking issues.
|
|
184
|
+
|
|
185
|
+
### Enabling Debug Logging
|
|
186
|
+
|
|
187
|
+
Debug logging automatically enables on `localhost`, or you can manually enable it:
|
|
188
|
+
|
|
189
|
+
```html
|
|
190
|
+
<!-- Enable debug logging on any domain -->
|
|
191
|
+
<script src="https://cdn.jsdelivr.net/npm/@kylelogue/eventfoundry-tracker@0.4.0/dist/tracker.min.js"
|
|
192
|
+
data-site-key="YOUR_SITE_KEY_HERE"
|
|
193
|
+
data-measurement-id="G-XXXXXXXXXX"
|
|
194
|
+
data-dev-mode="true"
|
|
195
|
+
async></script>
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Debug Console Messages
|
|
199
|
+
|
|
200
|
+
When dev mode is enabled, the tracker logs helpful debugging information:
|
|
201
|
+
|
|
202
|
+
**Event Firing:**
|
|
203
|
+
```
|
|
204
|
+
EventFoundry: Firing event button_click {event_category: "EventFoundry", ...}
|
|
205
|
+
```
|
|
206
|
+
Indicates an event is about to be sent (or logged in dev mode).
|
|
207
|
+
|
|
208
|
+
**Non-Matching Clicks:**
|
|
209
|
+
```
|
|
210
|
+
EventFoundry: Click on <button class="test"> matched 0 events
|
|
211
|
+
```
|
|
212
|
+
The clicked element doesn't match any of your event selectors. Check your event definitions to ensure the selector is correct.
|
|
213
|
+
|
|
214
|
+
**Editor Mode:**
|
|
215
|
+
```
|
|
216
|
+
EventFoundry: Click ignored (editor mode active, not in preview)
|
|
217
|
+
```
|
|
218
|
+
Clicks are ignored when the editor is active to prevent false events during element selection.
|
|
219
|
+
|
|
220
|
+
**Critical Errors (Always Logged):**
|
|
221
|
+
```
|
|
222
|
+
EventFoundry: gtag not available - is GA4 installed?
|
|
223
|
+
```
|
|
224
|
+
Google Analytics is not installed or was blocked. Verify your GA4 script is loading correctly.
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
EventFoundry: Invalid selector ".some[invalid:selector" - SyntaxError: ...
|
|
228
|
+
```
|
|
229
|
+
One of your event selectors is malformed. The tracker validates all selectors at initialization and logs warnings for each invalid selector.
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
🚨 EventFoundry: No valid event selectors found - tracking disabled!
|
|
233
|
+
```
|
|
234
|
+
**Critical**: ALL event selectors are invalid. The tracker will not attach any click listeners. Common causes:
|
|
235
|
+
- Unsupported CSS pseudo-classes (e.g., `:has()` in older browsers)
|
|
236
|
+
- Syntax errors in selectors
|
|
237
|
+
- Browser compatibility issues
|
|
238
|
+
|
|
239
|
+
If this error appears with cached data, the tracker will automatically clear the cache and refetch fresh definitions from the API.
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
EventFoundry: 2 of 10 selectors are invalid and will be skipped
|
|
243
|
+
```
|
|
244
|
+
Some (but not all) selectors are invalid. Tracking will continue for valid selectors, but invalid ones will be skipped. Check the console warnings above to see which selectors failed validation.
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
EventFoundry: Multiple events matched, only firing first: ["Event 1", "Event 2"]
|
|
248
|
+
```
|
|
249
|
+
Multiple events matched the same click. Consider making your selectors more specific.
|
|
250
|
+
|
|
251
|
+
### Common Debugging Scenarios
|
|
252
|
+
|
|
253
|
+
**Problem: "Events aren't showing in GA4"**
|
|
254
|
+
|
|
255
|
+
1. Enable dev mode and check console logs
|
|
256
|
+
2. Click the tracked element and look for:
|
|
257
|
+
- `Firing event ...` → Event is working, wait 24-48hrs for GA4 to show data
|
|
258
|
+
- `matched 0 events` → Your selector doesn't match the element
|
|
259
|
+
- `gtag not available` → GA4 script is blocked or missing
|
|
260
|
+
3. Use browser DevTools to verify your selector matches the element:
|
|
261
|
+
```javascript
|
|
262
|
+
document.querySelector('.your-selector') // Should return the element
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Problem: "Click doesn't trigger any logs"**
|
|
266
|
+
|
|
267
|
+
- Check that the tracker loaded: look for `✓ EventFoundry tracker loaded` in console
|
|
268
|
+
- Verify your site key is correct: `data-site-key="..."`
|
|
269
|
+
- Check browser console for errors during tracker initialization
|
|
270
|
+
|
|
271
|
+
**Problem: "Events fire in preview but not on live site"**
|
|
272
|
+
|
|
273
|
+
- Check if GA4 script is being blocked by ad blockers
|
|
274
|
+
- Enable dev mode on live site to see `gtag not available` errors
|
|
275
|
+
- Verify `data-measurement-id` matches your GA4 property
|
|
276
|
+
|
|
180
277
|
## Editor Integration
|
|
181
278
|
|
|
182
279
|
EventFoundry Tracker includes a sophisticated visual editor for defining events directly on your website.
|
package/dist/tracker.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var EventFoundry=(()=>{var h=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames,F=Object.getOwnPropertySymbols;var D=Object.prototype.hasOwnProperty,H=Object.prototype.propertyIsEnumerable;var I=(e,t,n)=>t in e?h(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,_=(e,t)=>{for(var n in t||(t={}))D.call(t,n)&&I(e,n,t[n]);if(F)for(var n of F(t))H.call(t,n)&&I(e,n,t[n]);return e};var K=(e,t)=>{for(var n in t)h(e,n,{get:t[n],enumerable:!0})},q=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of j(t))!D.call(e,r)&&r!==n&&h(e,r,{get:()=>t[r],enumerable:!(o=W(t,r))||o.enumerable});return e};var z=e=>q(h({},"__esModule",{value:!0}),e);var g=(e,t,n)=>new Promise((o,r)=>{var a=d=>{try{c(n.next(d))}catch(w){r(w)}},s=d=>{try{c(n.throw(d))}catch(w){r(w)}},c=d=>d.done?o(d.value):Promise.resolve(d.value).then(a,s);c((n=n.apply(e,t)).next())});var Ee={};K(Ee,{reloadEventDefinitions:()=>L});var m=null;function y(){return m}function J(){return["http://localhost","https://eventfoundry.app"]}function P(e){return J().some(n=>n==="http://localhost"?e.startsWith("http://localhost"):e===n)}function A(){try{return window.self!==window.top}catch(e){return!0}}function T(){A()&&(console.log("EventFoundry: Running in iframe, waiting for editor activation"),console.log("[DEBUG] Registering message listener..."),window.addEventListener("message",e=>{console.log("[DEBUG] Raw message received:",{data:e.data,origin:e.origin,isArray:Array.isArray(e.data)});let t=e.data;Array.isArray(t)&&t.length>0&&(console.log("[DEBUG] Unwrapping array-wrapped message"),t=t[0]),console.log("[DEBUG] After unwrapping:",t);let n=t==null?void 0:t.type,o=["ENTER_EDIT_MODE","ENABLE_PREVIEW","DISABLE_PREVIEW","RELOAD_CONFIG"];if(console.log("[DEBUG] Message type check:",{messageType:n,isValid:o.includes(n)}),!(!n||!o.includes(n))){if(console.log("[DEBUG] EventFoundry message received:",{type:n,origin:e.origin,isAllowed:P(e.origin)}),!P(e.origin)){console.warn("EventFoundry: Rejected postMessage from untrusted origin:",e.origin);return}switch(m||(m=e.origin,console.log("EventFoundry: Parent origin established:",m)),t.type){case"ENTER_EDIT_MODE":console.log("\u2190 ENTER_EDIT_MODE received"),Y();break;case"ENABLE_PREVIEW":console.log("\u2190 ENABLE_PREVIEW received"),Q();break;case"DISABLE_PREVIEW":console.log("\u2190 DISABLE_PREVIEW received"),X();break;case"RELOAD_CONFIG":console.log("\u2190 RELOAD_CONFIG received"),L();break}}}),console.log("[DEBUG] Message listener registered successfully"),setTimeout(()=>{window.parent&&(window.parent.postMessage({type:"IFRAME_READY"},"*"),console.log("\u2192 IFRAME_READY sent to parent"))},100))}function Y(){M()}function Q(){console.log("EventFoundry: Enabling Preview Mode"),$()}function X(){console.log("EventFoundry: Disabling Preview Mode (Edit Mode active)"),O()}var u=null,p=!1,E=null,f=!1;function R(){return p}function N(){return f}function Z(){return["http://localhost","https://eventfoundry.app"]}function ee(e){return Z().some(n=>n==="http://localhost"?e.startsWith("http://localhost"):e===n)}function M(){if(p)return;p=!0;let e=document.createElement("style");e.textContent=` .eventfoundry-highlight { outline: 2px solid #3498db !important; outline-offset: 2px; cursor: pointer !important; } .eventfoundry-test-highlight { outline: 3px solid #e74c3c !important; outline-offset: 3px; background-color: rgba(231, 76, 60, 0.1) !important; } .eventfoundry-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 999998; pointer-events: none; cursor: crosshair; } body.eventfoundry-edit-mode, body.eventfoundry-edit-mode * { cursor: crosshair !important; } `,document.head.appendChild(e);let t=document.createElement("div");t.className="eventfoundry-overlay",document.body.appendChild(t),E=t,document.body.classList.add("eventfoundry-edit-mode"),document.body.addEventListener("mouseover",n=>{f||n.target.classList.contains("eventfoundry-overlay")||(u&&u.classList.remove("eventfoundry-highlight"),n.target.classList.add("eventfoundry-highlight"),u=n.target)},!0),document.body.addEventListener("mouseout",n=>{f||n.target.classList.contains("eventfoundry-overlay")||n.target.classList.remove("eventfoundry-highlight")},!0),document.body.addEventListener("click",n=>{if(n.target.classList.contains("eventfoundry-overlay"))return;if(f){console.log("EventFoundry: Preview Mode - allowing click to pass through");return}n.preventDefault(),n.stopPropagation();let o=n.target,r="";o.className&&typeof o.className=="string"&&(r=o.className.trim().split(/\s+/).filter(d=>!d.startsWith("eventfoundry-")).join(" "));let a=window.location.pathname+window.location.search+window.location.hash,s={tagName:o.tagName.toLowerCase(),text:o.textContent.trim().substring(0,50),id:o.id,className:r,selector:le(o),page_path:a},c=y();c?(window.parent.postMessage({type:"ELEMENT_SELECTED",element:s},c),console.log("\u2192 ELEMENT_SELECTED sent to parent")):console.warn("EventFoundry: Cannot send ELEMENT_SELECTED - parent origin not established")},!0),window.addEventListener("message",n=>{if(ee(n.origin)&&(n.data.type==="HIGHLIGHT_SELECTOR"&&(console.log("\u2190 HIGHLIGHT_SELECTOR received:",n.data.selector),de(n.data.selector)),n.data.type==="COUNT_MATCHES")){let o=n.data.selector,r=0;try{r=document.querySelectorAll(o).length}catch(s){r=0}let a=y();a&&window.parent.postMessage({type:"MATCH_COUNT_RESULT",selector:o,count:r},a)}})}function i(e){return e?e.replace(/([!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~])/g,"\\$1"):""}function te(e){return e?!!(/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/i.test(e)||/\d{13}/.test(e)||/^[a-f0-9]{16,}$/i.test(e)||/-\d{4,}$/.test(e)):!1}function ne(e,t){try{let n=document.querySelectorAll(t);return n.length===1&&n[0]===e}catch(n){return!1}}function S(e){return!e.className||typeof e.className!="string"?[]:e.className.trim().split(/\s+/).filter(t=>t&&!t.startsWith("eventfoundry-"))}function k(e,t=!0){let n=e.parentElement;if(!n)return null;let o=S(n);return t&&o.length>0?`.${i(o[0])}`:n.tagName.toLowerCase()}function l(e,t,n,o){return ne(o,t)?(e.push({selector:t,priority:n}),!0):!1}function oe(e){let t=[];if(e.id&&!te(e.id)){let n=`#${i(e.id)}`;l(t,n,100,e)}return t}function re(e){let t=[],n=Array.from(e.attributes).filter(o=>o.name.startsWith("data-")&&o.value);for(let o of n){let r=`[${o.name}="${i(o.value)}"]`;if(l(t,r,90,e))break}return t}function ae(e){let t=[],n=S(e);if(n.length===0)return t;let o=e.tagName.toLowerCase();for(let r of n){let a=`${o}.${i(r)}`;if(l(t,a,85,e))break}if(n.length>=2){let r=`.${i(n[0])}.${i(n[1])}`;if(l(t,r,82,e),n.length>=3){let a=`.${i(n[0])}.${i(n[1])}.${i(n[2])}`;l(t,a,82,e)}}for(let r of n){let a=`.${i(r)}`;if(l(t,a,80,e))break}return t}function se(e){let t=[],n=e.tagName.toLowerCase(),o=["type","name","href","role","aria-label"];for(let r of o){let a=e.getAttribute(r);if(a){let s=`${n}[${r}="${i(a)}"]`;if(l(t,s,70,e))break}}return t}function ie(e){let t=[],n=k(e,!0);if(!n)return t;let o=e.tagName.toLowerCase(),r=S(e);if(r.length>0){let s=`${n} .${i(r[0])}`;l(t,s,75,e)}if(r.length>0){let s=`${n} ${o}.${i(r[0])}`;l(t,s,72,e)}let a=`${n} ${o}`;return l(t,a,65,e),t}function ce(e){let t=[],n=e.tagName.toLowerCase(),o=e.parentElement;if(!o)return[{selector:n,priority:10}];let r=k(e,!0),s=Array.from(o.children).indexOf(e)+1,c=`${r} ${n}:nth-child(${s})`;return l(t,c,50,e),t}function le(e){let t=[];return t.push(...oe(e)),t.push(...re(e)),t.push(...ae(e)),t.push(...se(e)),t.push(...ie(e)),t.push(...ce(e)),t.length>0?(t.sort((n,o)=>o.priority-n.priority),t[0].selector):e.tagName.toLowerCase()}function de(e){document.querySelectorAll(".eventfoundry-test-highlight").forEach(t=>{t.classList.remove("eventfoundry-test-highlight")});try{let t=document.querySelectorAll(e);t.forEach(n=>{n.classList.add("eventfoundry-test-highlight")}),setTimeout(()=>{t.forEach(n=>{n.classList.remove("eventfoundry-test-highlight")})},3e3)}catch(t){console.error("EventFoundry: Invalid selector",e,t)}}function $(){if(!p){console.warn("EventFoundry: Cannot enable preview - overlay not active");return}f=!0,console.log("EventFoundry: Preview Mode enabled - all interactions allowed"),E&&(E.style.display="none"),document.body.classList.remove("eventfoundry-edit-mode"),u&&(u.classList.remove("eventfoundry-highlight"),u=null)}function O(){if(!p){console.warn("EventFoundry: Cannot disable preview - overlay not active");return}f=!1,console.log("EventFoundry: Preview Mode disabled - Edit Mode active"),E&&(E.style.display=""),document.body.classList.add("eventfoundry-edit-mode")}var x=console.log;function v(e,...t){e&&x&&x(...t)}function C(e,t=!1){!e||e.length===0||document.addEventListener("click",n=>{if(R()&&!N())return;let o=e.filter(s=>{try{return n.target.closest(s.selector)!==null}catch(c){return console.warn("EventFoundry: Invalid selector",s.selector,c.message),!1}});if(o.length===0)return;let r=o[0],a=_({event_category:"EventFoundry",event_label:r.name,transport_type:"beacon"},r.gaEventParams);if(v(t,"EventFoundry [DEV]: Tracked event (not sent to GA4)",r.gaEventName,a),t||window.gtag("event",r.gaEventName,a),N())try{let s=y();s?(window.parent.postMessage({type:"EVENT_FIRED",timestamp:Date.now(),eventName:r.name,gaEventName:r.gaEventName,selector:r.selector,params:a,pagePath:window.location.pathname},s),console.log("\u2192 EVENT_FIRED sent to parent")):console.warn("EventFoundry: Cannot send EVENT_FIRED - parent origin not established")}catch(s){console.warn("EventFoundry: Failed to send EVENT_FIRED postMessage",s)}o.length>1&&console.warn("EventFoundry: Multiple events matched, only firing first:",o.map(s=>s.name))},!0)}var V=window.location.hostname==="localhost"||window.location.hostname==="127.0.0.1",ue=V?"http://localhost/api/tracking/events":"https://eventfoundry.app/api/tracking/events",fe=3600*1e3;function b(e){return`eventfoundry_definitions_${e}`}function B(){let e=document.currentScript||document.querySelector("script[data-site-key]");if(!e)return console.error("EventFoundry: Could not find script tag"),null;let t=e.getAttribute("data-dev-mode"),n=t==="false"?!1:V||t==="true";return{siteKey:e.getAttribute("data-site-key"),measurementId:e.getAttribute("data-measurement-id"),devMode:n}}function ge(e){return g(this,null,function*(){if(window.gtag&&typeof window.gtag=="function")return{hasGtag:!0,wasInjected:!1};if(!e)return console.warn("EventFoundry: No GA4 detected and no measurement ID provided. Events will not be tracked."),{hasGtag:!1,wasInjected:!1};let t=document.createElement("script");t.async=!0,t.src=`https://www.googletagmanager.com/gtag/js?id=${e}`,document.head.appendChild(t),window.dataLayer=window.dataLayer||[];function n(){dataLayer.push(arguments)}return window.gtag=n,n("js",new Date),n("config",e),yield new Promise(o=>{t.onload=o,setTimeout(o,5e3)}),{hasGtag:!0,wasInjected:!0}})}function G(){return g(this,null,function*(){let e=B();if(!e||!e.siteKey){console.error("EventFoundry: No site key provided");return}let{siteKey:t,measurementId:n,devMode:o}=e;console.log("\u2713 EventFoundry tracker loaded"),A()&&T();let{hasGtag:r,wasInjected:a}=yield ge(n);if(!r){console.error("EventFoundry: Cannot track events without GA4");return}console.log(a?"\u2713 GA4 injected successfully":"\u2713 GA4 detected"),v(o,"\u26A0 Dev mode: Events disabled (v0.3.8)"),v(!o,"\u2713 Production mode: Events enabled (v0.3.8)");try{let c=(yield U(t)).events;C(c,o)}catch(s){console.error("EventFoundry: Failed to initialize:",s)}})}function U(e){return g(this,null,function*(){let t=ye(e);if(t)return t;let n=yield fetch(`${ue}?siteKey=${e}`);if(!n.ok)throw new Error(`API returned ${n.status}`);let o=yield n.json();return pe(e,o),o})}function ye(e){try{let t=b(e),n=localStorage.getItem(t);if(!n)return null;let{data:o,timestamp:r}=JSON.parse(n);return Date.now()-r>fe?(localStorage.removeItem(t),null):o}catch(t){return console.warn("EventFoundry: Cache read failed:",t),null}}function pe(e,t){try{let n=b(e),o={data:t,timestamp:Date.now()};localStorage.setItem(n,JSON.stringify(o))}catch(n){console.warn("EventFoundry: Cache write failed:",n)}}function L(){return g(this,null,function*(){let e=B();if(!e||!e.siteKey){console.error("EventFoundry: No site key available for reload");return}let{siteKey:t,devMode:n}=e;try{let o=b(t);localStorage.removeItem(o),console.log("EventFoundry: Cache cleared, reloading definitions")}catch(o){console.warn("EventFoundry: Failed to clear cache",o)}try{let r=(yield U(t)).events;C(r,n),console.log("EventFoundry: Definitions reloaded successfully")}catch(o){console.error("EventFoundry: Failed to reload definitions",o)}})}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",G):G();return z(Ee);})();
|
|
1
|
+
var EventFoundry=(()=>{var m=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var J=Object.getOwnPropertyNames,$=Object.getOwnPropertySymbols;var T=Object.prototype.hasOwnProperty,Y=Object.prototype.propertyIsEnumerable;var P=(e,t,n)=>t in e?m(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,D=(e,t)=>{for(var n in t||(t={}))T.call(t,n)&&P(e,n,t[n]);if($)for(var n of $(t))Y.call(t,n)&&P(e,n,t[n]);return e};var Q=(e,t)=>{for(var n in t)m(e,n,{get:t[n],enumerable:!0})},X=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of J(t))!T.call(e,r)&&r!==n&&m(e,r,{get:()=>t[r],enumerable:!(o=U(t,r))||o.enumerable});return e};var Z=e=>X(m({},"__esModule",{value:!0}),e);var h=(e,t,n)=>new Promise((o,r)=>{var a=i=>{try{c(n.next(i))}catch(f){r(f)}},s=i=>{try{c(n.throw(i))}catch(f){r(f)}},c=i=>i.done?o(i.value):Promise.resolve(i.value).then(a,s);c((n=n.apply(e,t)).next())});var Fe={};Q(Fe,{reloadEventDefinitions:()=>S});var w=null;function E(){return w}function ee(){return["http://localhost","https://eventfoundry.app"]}function te(e){return ee().some(n=>n==="http://localhost"?e.startsWith("http://localhost"):e===n)}function C(){try{return window.self!==window.top}catch(e){return!0}}function O(){C()&&(console.log("EventFoundry: Running in iframe, waiting for editor activation"),window.addEventListener("message",e=>{let t=e.data,n=t==null?void 0:t.type;if(!(!n||!["ENTER_EDIT_MODE","ENABLE_PREVIEW","DISABLE_PREVIEW","RELOAD_CONFIG"].includes(n))){if(!te(e.origin)){console.warn("EventFoundry: Rejected postMessage from untrusted origin:",e.origin);return}switch(w||(w=e.origin,console.log("EventFoundry: Parent origin established:",w)),t.type){case"ENTER_EDIT_MODE":console.log("\u2190 ENTER_EDIT_MODE received"),ne();break;case"ENABLE_PREVIEW":console.log("\u2190 ENABLE_PREVIEW received"),oe();break;case"DISABLE_PREVIEW":console.log("\u2190 DISABLE_PREVIEW received"),re();break;case"RELOAD_CONFIG":console.log("\u2190 RELOAD_CONFIG received"),S();break}}}),setTimeout(()=>{window.parent&&(window.parent.postMessage({type:"IFRAME_READY"},"*"),console.log("\u2192 IFRAME_READY sent to parent"))},100))}function ne(){M()}function oe(){console.log("EventFoundry: Enabling Preview Mode"),k()}function re(){console.log("EventFoundry: Disabling Preview Mode (Edit Mode active)"),R()}var g=null,y=!1,p=null,v=!1;function x(){return y}function I(){return v}function ae(){return["http://localhost","https://eventfoundry.app"]}function se(e){return ae().some(n=>n==="http://localhost"?e.startsWith("http://localhost"):e===n)}function M(){if(y)return;y=!0;let e=document.createElement("style");e.textContent=` .eventfoundry-highlight { outline: 2px solid #3498db !important; outline-offset: 2px; cursor: pointer !important; } .eventfoundry-test-highlight { outline: 3px solid #e74c3c !important; outline-offset: 3px; background-color: rgba(231, 76, 60, 0.1) !important; } .eventfoundry-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 999998; pointer-events: none; cursor: crosshair; } body.eventfoundry-edit-mode, body.eventfoundry-edit-mode * { cursor: crosshair !important; } `,document.head.appendChild(e);let t=document.createElement("div");t.className="eventfoundry-overlay",document.body.appendChild(t),p=t,document.body.classList.add("eventfoundry-edit-mode"),document.body.addEventListener("mouseover",n=>{v||n.target.classList.contains("eventfoundry-overlay")||(g&&g.classList.remove("eventfoundry-highlight"),n.target.classList.add("eventfoundry-highlight"),g=n.target)},!0),document.body.addEventListener("mouseout",n=>{v||n.target.classList.contains("eventfoundry-overlay")||n.target.classList.remove("eventfoundry-highlight")},!0),document.body.addEventListener("click",n=>{if(n.target.classList.contains("eventfoundry-overlay")||v)return;n.preventDefault(),n.stopPropagation();let o=n.target,r="";o.className&&typeof o.className=="string"&&(r=o.className.trim().split(/\s+/).filter(i=>!i.startsWith("eventfoundry-")).join(" "));let a=window.location.pathname+window.location.search+window.location.hash,s={tagName:o.tagName.toLowerCase(),text:o.textContent.trim().substring(0,50),id:o.id,className:r,selector:he(o),page_path:a},c=E();c?(window.parent.postMessage({type:"ELEMENT_SELECTED",element:s},c),console.log("\u2192 ELEMENT_SELECTED sent to parent")):console.warn("EventFoundry: Cannot send ELEMENT_SELECTED - parent origin not established")},!0),window.addEventListener("message",n=>{if(se(n.origin)&&(n.data.type==="HIGHLIGHT_SELECTOR"&&(console.log("\u2190 HIGHLIGHT_SELECTOR received:",n.data.selector),Ee(n.data.selector)),n.data.type==="COUNT_MATCHES")){let o=n.data.selector,r=0;try{r=document.querySelectorAll(o).length}catch(s){r=0}let a=E();a&&window.parent.postMessage({type:"MATCH_COUNT_RESULT",selector:o,count:r},a)}})}function l(e){return e?e.replace(/([!"#$%&'()*+,.\/:;<=>?@[\\\]^`{|}~])/g,"\\$1"):""}function ie(e){return e?!!(/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/i.test(e)||/\d{13}/.test(e)||/^[a-f0-9]{16,}$/i.test(e)||/-\d{4,}$/.test(e)):!1}function ce(e,t){try{let n=document.querySelectorAll(t);return n.length===1&&n[0]===e}catch(n){return!1}}function N(e){return!e.className||typeof e.className!="string"?[]:e.className.trim().split(/\s+/).filter(t=>t&&!t.startsWith("eventfoundry-"))}function G(e,t=!0){let n=e.parentElement;if(!n)return null;let o=N(n);return t&&o.length>0?`.${l(o[0])}`:n.tagName.toLowerCase()}function d(e,t,n,o){return ce(o,t)?(e.push({selector:t,priority:n}),!0):!1}function le(e){let t=[];if(e.id&&!ie(e.id)){let n=`#${l(e.id)}`;d(t,n,100,e)}return t}function de(e){let t=[],n=Array.from(e.attributes).filter(o=>o.name.startsWith("data-")&&o.value);for(let o of n){let r=`[${o.name}="${l(o.value)}"]`;if(d(t,r,90,e))break}return t}function ue(e){let t=[],n=N(e);if(n.length===0)return t;let o=e.tagName.toLowerCase();for(let r of n){let a=`${o}.${l(r)}`;if(d(t,a,85,e))break}if(n.length>=2){let r=`.${l(n[0])}.${l(n[1])}`;if(d(t,r,82,e),n.length>=3){let a=`.${l(n[0])}.${l(n[1])}.${l(n[2])}`;d(t,a,82,e)}}for(let r of n){let a=`.${l(r)}`;if(d(t,a,80,e))break}return t}function fe(e){let t=[],n=e.tagName.toLowerCase(),o=["type","name","href","role","aria-label"];for(let r of o){let a=e.getAttribute(r);if(a){let s=`${n}[${r}="${l(a)}"]`;if(d(t,s,70,e))break}}return t}function ge(e){let t=[],n=G(e,!0);if(!n)return t;let o=e.tagName.toLowerCase(),r=N(e);if(r.length>0){let s=`${n} .${l(r[0])}`;d(t,s,75,e)}if(r.length>0){let s=`${n} ${o}.${l(r[0])}`;d(t,s,72,e)}let a=`${n} ${o}`;return d(t,a,65,e),t}function ve(e){let t=[],n=e.tagName.toLowerCase(),o=e.parentElement;if(!o)return[{selector:n,priority:10}];let r=G(e,!0),s=Array.from(o.children).indexOf(e)+1,c=`${r} ${n}:nth-child(${s})`;return d(t,c,50,e),t}function he(e){let t=[];return t.push(...le(e)),t.push(...de(e)),t.push(...ue(e)),t.push(...fe(e)),t.push(...ge(e)),t.push(...ve(e)),t.length>0?(t.sort((n,o)=>o.priority-n.priority),t[0].selector):e.tagName.toLowerCase()}function Ee(e){document.querySelectorAll(".eventfoundry-test-highlight").forEach(t=>{t.classList.remove("eventfoundry-test-highlight")});try{let t=document.querySelectorAll(e);t.forEach(n=>{n.classList.add("eventfoundry-test-highlight")}),setTimeout(()=>{t.forEach(n=>{n.classList.remove("eventfoundry-test-highlight")})},3e3)}catch(t){console.error("EventFoundry: Invalid selector",e,t)}}function k(){if(!y){console.warn("EventFoundry: Cannot enable preview - overlay not active");return}v=!0,console.log("EventFoundry: Preview Mode enabled - all interactions allowed"),p&&(p.style.display="none"),document.body.classList.remove("eventfoundry-edit-mode"),g&&(g.classList.remove("eventfoundry-highlight"),g=null)}function R(){if(!y){console.warn("EventFoundry: Cannot disable preview - overlay not active");return}v=!1,console.log("EventFoundry: Preview Mode disabled - Edit Mode active"),p&&(p.style.display=""),document.body.classList.add("eventfoundry-edit-mode")}var j=console.log;function u(e,...t){e&&j&&j(...t)}var F=null;function ye(e){let t=[],n=[];return e.forEach(o=>{try{document.querySelector(o.selector),t.push(o)}catch(r){console.warn(`EventFoundry: Invalid selector "${o.selector}" - ${r.message}`),n.push({selector:o.selector,error:r.message,name:o.name})}}),{validDefs:t,invalidDefs:n}}function b(e,t=!1){if(!e||e.length===0)return!1;F&&F.abort();let{validDefs:n,invalidDefs:o}=ye(e);return n.length===0?(console.error("\u{1F6A8} EventFoundry: No valid event selectors found - tracking disabled!"),console.error("Invalid selectors:",o),!1):(o.length>0&&console.warn(`EventFoundry: ${o.length} of ${e.length} selectors are invalid and will be skipped`),F=new AbortController,document.addEventListener("click",r=>{if(x()&&!I()){u(t,"EventFoundry: Click ignored (editor mode active, not in preview)");return}let a=n.filter(i=>r.target.closest(i.selector)!==null);if(a.length===0){u(t,"EventFoundry: Click on",r.target,"matched 0 events");return}let s=a[0],c=D({event_category:"EventFoundry",event_label:s.name,transport_type:"beacon"},s.gaEventParams);if(u(t,"EventFoundry: Firing event",s.gaEventName,c),!t){if(typeof window.gtag!="function"){console.error("EventFoundry: gtag not available - is GA4 installed?");return}window.gtag("event",s.gaEventName,c)}if(I())try{let i=E();i?(window.parent.postMessage({type:"EVENT_FIRED",timestamp:Date.now(),eventName:s.name,gaEventName:s.gaEventName,selector:s.selector,params:c,pagePath:window.location.pathname},i),console.log("\u2192 EVENT_FIRED sent to parent")):console.warn("EventFoundry: Cannot send EVENT_FIRED - parent origin not established")}catch(i){console.warn("EventFoundry: Failed to send EVENT_FIRED postMessage",i)}a.length>1&&console.warn("EventFoundry: Multiple events matched, only firing first:",a.map(i=>i.name))},{capture:!0,signal:F.signal}),!0)}var K=window.location.hostname==="localhost"||window.location.hostname==="127.0.0.1",V=K?"http://localhost/api/tracking/events":"https://eventfoundry.app/api/tracking/events";function A(e){return`eventfoundry_definitions_${e}`}function _(e){return`eventfoundry_etag_${e}`}function q(){let e=document.currentScript||document.querySelector("script[data-site-key]");if(!e)return console.error("EventFoundry: Could not find script tag"),null;let t=e.getAttribute("data-dev-mode"),n=t==="false"?!1:K||t==="true";return{siteKey:e.getAttribute("data-site-key"),measurementId:e.getAttribute("data-measurement-id"),devMode:n}}function pe(e){return h(this,null,function*(){if(window.gtag&&typeof window.gtag=="function")return{hasGtag:!0,wasInjected:!1};if(!e)return console.warn("EventFoundry: No GA4 detected and no measurement ID provided. Events will not be tracked."),{hasGtag:!1,wasInjected:!1};let t=document.createElement("script");return t.async=!0,t.src=`https://www.googletagmanager.com/gtag/js?id=${e}`,document.head.appendChild(t),window.dataLayer=window.dataLayer||[],yield new Promise((n,o)=>{let r=!1;t.onload=()=>{r||(r=!0,n())},t.onerror=()=>{r||(r=!0,console.error("EventFoundry: Failed to load gtag script"),o(new Error("gtag script failed to load")))},setTimeout(()=>{r||(r=!0,console.warn("EventFoundry: gtag script load timeout after 10s"),n())},1e4)}).catch(()=>({hasGtag:!1,wasInjected:!1})),typeof window.gtag!="function"?(console.error("EventFoundry: gtag not available after load - events will not fire"),{hasGtag:!1,wasInjected:!1}):(window.gtag("js",new Date),window.gtag("config",e),{hasGtag:!0,wasInjected:!0})})}function W(){return h(this,null,function*(){let e=q();if(!e||!e.siteKey){console.error("EventFoundry: No site key provided");return}let{siteKey:t,measurementId:n,devMode:o}=e;console.log("\u2713 EventFoundry tracker loaded"),C()&&O();let{hasGtag:r,wasInjected:a}=yield pe(n);if(!r){console.error("EventFoundry: Cannot track events without GA4");return}console.log(a?"\u2713 GA4 injected successfully":"\u2713 GA4 detected"),u(o,"\u26A0 Dev mode: Events disabled (v0.5.0)"),u(!o,"\u2713 Production mode: Events enabled (v0.5.0)");try{let s=yield L(t),c=s.events;if(!b(c,o)&&s._fromCache){console.log("EventFoundry: Tracking failed with cached data, clearing cache and refetching..."),B(t);let z=(yield L(t)).events;b(z,o)}}catch(s){console.error("EventFoundry: Failed to initialize:",s)}})}function L(e){return h(this,null,function*(){let t=me(e),n=we(e),o={};n&&(o["If-None-Match"]=n);let r=yield fetch(`${V}?siteKey=${e}`,{headers:o});if(r.status===304){if(t)return t;let c=yield fetch(`${V}?siteKey=${e}`);if(!c.ok)throw new Error(`API returned ${c.status}`);let i=yield c.json(),f=c.headers.get("etag");return H(e,i,f),i}if(!r.ok)throw new Error(`API returned ${r.status}`);let a=yield r.json(),s=r.headers.get("etag");return H(e,a,s),a})}function me(e){try{let t=A(e),n=localStorage.getItem(t);if(!n)return null;let o=JSON.parse(n);return o._fromCache=!0,o}catch(t){return console.warn("EventFoundry: Cache read failed:",t),null}}function we(e){try{let t=_(e);return localStorage.getItem(t)}catch(t){return console.warn("EventFoundry: ETag read failed:",t),null}}function H(e,t,n){try{let o=A(e),r=_(e);localStorage.setItem(o,JSON.stringify(t)),n&&localStorage.setItem(r,n)}catch(o){console.warn("EventFoundry: Cache write failed:",o)}}function B(e){try{let t=A(e),n=_(e);localStorage.removeItem(t),localStorage.removeItem(n)}catch(t){console.warn("EventFoundry: Failed to clear cache:",t)}}function S(){return h(this,null,function*(){let e=q();if(!e||!e.siteKey){console.error("EventFoundry: No site key available for reload");return}let{siteKey:t,devMode:n}=e;console.log("EventFoundry: Cache cleared, reloading definitions"),B(t);try{let r=(yield L(t)).events;b(r,n),console.log("EventFoundry: Definitions reloaded successfully")}catch(o){console.error("EventFoundry: Failed to reload definitions",o)}})}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",W):W();return Z(Fe);})();
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kylelogue/eventfoundry-tracker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "EventFoundry tracking script for custom GA4 event tracking",
|
|
5
5
|
"main": "dist/tracker.min.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"dist"
|
|
8
8
|
],
|
|
9
9
|
"scripts": {
|
|
10
|
-
"build": "node build.js",
|
|
11
|
-
"dev": "node build.js
|
|
10
|
+
"build": "node build.js --production",
|
|
11
|
+
"dev": "node build.js",
|
|
12
12
|
"test": "echo \"No tests yet\"",
|
|
13
13
|
"prepublishOnly": "npm run build"
|
|
14
14
|
},
|