@accelerated-agency/visual-editor 0.3.8 → 0.4.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/dist/index.js CHANGED
@@ -4808,6 +4808,7 @@ function PlatformVisualEditorV2({
4808
4808
  embeddedGlobalKey = "__CONVERSION_EMBEDDED__",
4809
4809
  proxyBaseUrl = "",
4810
4810
  strictObserverFreeze = false,
4811
+ trackingMarkers = [],
4811
4812
  className = "fixed inset-0 z-[9999] flex flex-col bg-white",
4812
4813
  editorClassName = "flex-1 min-h-0",
4813
4814
  showHeader = true,
@@ -4870,11 +4871,11 @@ function PlatformVisualEditorV2({
4870
4871
  pageUrl: experiment?.pageUrl,
4871
4872
  editorPassword: experiment?.editorPassword,
4872
4873
  strictObserverFreeze: !!strictObserverFreeze,
4874
+ trackingMarkers: Array.isArray(trackingMarkers) ? trackingMarkers.filter((m) => typeof m === "string" && m.trim().length > 0) : [],
4873
4875
  variations: experiment?.variations ?? []
4874
4876
  }),
4875
- [experiment, strictObserverFreeze]
4877
+ [experiment, strictObserverFreeze, trackingMarkers]
4876
4878
  );
4877
- console.log("loadPayload", loadPayload);
4878
4879
  const editorSrc = useMemo(() => {
4879
4880
  const safeBaseUrl = normalizeProxyBaseUrl(proxyBaseUrl);
4880
4881
  return safeBaseUrl ? `${safeBaseUrl}/vvveb-editor` : "/vvveb-editor";
package/dist/vite.cjs CHANGED
@@ -25,6 +25,94 @@ var SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED_RAW = process.env.SCRAPERAPI_REQUEST
25
25
  var SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED = !["0", "false", "no"].includes(
26
26
  SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED_RAW.toLowerCase()
27
27
  );
28
+ var DEFAULT_TRACKING_MARKERS = [
29
+ "snowplow",
30
+ "taboola",
31
+ "googletagmanager",
32
+ "google-analytics",
33
+ "googleads",
34
+ "doubleclick",
35
+ "gtag(",
36
+ "ga(",
37
+ "fbq(",
38
+ "clarity",
39
+ "hotjar",
40
+ "segment.com",
41
+ "mixpanel",
42
+ "amplitude",
43
+ "fullstory",
44
+ "northbeam",
45
+ "nb-collector",
46
+ "/api/collect",
47
+ "/nb-collector",
48
+ '"r":"periodic"',
49
+ '"r": "periodic"'
50
+ ];
51
+ function normalizeTrackingMarkers(input) {
52
+ if (!Array.isArray(input)) return [];
53
+ const deduped = /* @__PURE__ */ new Set();
54
+ const aliases = {
55
+ tabola: "taboola"
56
+ };
57
+ for (let i = 0; i < input.length; i += 1) {
58
+ const raw = input[i];
59
+ if (typeof raw !== "string") continue;
60
+ const marker = raw.trim().toLowerCase();
61
+ if (!marker) continue;
62
+ deduped.add(aliases[marker] || marker);
63
+ }
64
+ return Array.from(deduped);
65
+ }
66
+ function mergeTrackingMarkers(extraMarkers) {
67
+ return normalizeTrackingMarkers([
68
+ ...DEFAULT_TRACKING_MARKERS,
69
+ ...normalizeTrackingMarkers(extraMarkers)
70
+ ]);
71
+ }
72
+ function parseTrackingMarkersParam(raw) {
73
+ if (!raw) return [];
74
+ try {
75
+ return normalizeTrackingMarkers(JSON.parse(raw));
76
+ } catch (_) {
77
+ return normalizeTrackingMarkers(
78
+ raw.split(",").map((v) => v.trim()).filter(Boolean)
79
+ );
80
+ }
81
+ }
82
+ function hasTrackingMarker(input, markers) {
83
+ const text = String(input || "").toLowerCase();
84
+ for (let i = 0; i < markers.length; i += 1) {
85
+ if (text.includes(markers[i])) return true;
86
+ }
87
+ return false;
88
+ }
89
+ function stripTrackingScriptsFromScrapedHtml(html, markers) {
90
+ let removedCount = 0;
91
+ let out = html;
92
+ out = out.replace(/<script\b[\s\S]*?<\/script>/gi, (tag) => {
93
+ const srcMatch = tag.match(/\bsrc\s*=\s*(["'])(.*?)\1/i);
94
+ const src = srcMatch?.[2] || "";
95
+ if (hasTrackingMarker(src, markers) || hasTrackingMarker(tag, markers)) {
96
+ removedCount += 1;
97
+ return "";
98
+ }
99
+ return tag;
100
+ });
101
+ out = out.replace(/<noscript\b[\s\S]*?<\/noscript>/gi, (tag) => {
102
+ if (!hasTrackingMarker(tag, markers)) return tag;
103
+ removedCount += 1;
104
+ return "";
105
+ });
106
+ if (removedCount > 0) {
107
+ out = out.replace(
108
+ /<head([^>]*)>/i,
109
+ `<head$1>
110
+ <meta name="conversion-editor-tracking-scripts-stripped" content="${removedCount}">
111
+ `
112
+ );
113
+ }
114
+ return out;
115
+ }
28
116
  var scraperProxyClientPromise = null;
29
117
  async function getScraperProxyClient() {
30
118
  if (scraperProxyClientPromise) return scraperProxyClientPromise;
@@ -2309,9 +2397,16 @@ function handleLoadExperiment(data) {
2309
2397
  lastLoadedProxyUrl = '';
2310
2398
  return;
2311
2399
  }
2400
+ var extraTrackingMarkers = Array.isArray(data && data.trackingMarkers)
2401
+ ? data.trackingMarkers.filter(function(m){return typeof m === 'string' && m.trim().length > 0;})
2402
+ : [];
2403
+ var trackingMarkersParam = extraTrackingMarkers.length
2404
+ ? '&trackingMarkers=' + encodeURIComponent(JSON.stringify(extraTrackingMarkers))
2405
+ : '';
2312
2406
  var proxyUrl = '/api/conversion-proxy?password=' + encodeURIComponent(data.editorPassword || '') +
2313
2407
  '&url=' + encodeURIComponent(pageUrl) +
2314
- '&strictObserverFreeze=' + encodeURIComponent(data && data.strictObserverFreeze ? '1' : '0');
2408
+ '&strictObserverFreeze=' + encodeURIComponent(data && data.strictObserverFreeze ? '1' : '0') +
2409
+ trackingMarkersParam;
2315
2410
 
2316
2411
  // Parent often re-posts load-experiment when React re-renders (new object identity) or
2317
2412
  // after mutations-changed. Reloading the iframe again wipes variant changesets mid-session.
@@ -5396,6 +5491,12 @@ function createVisualEditorMiddleware(options) {
5396
5491
  const url = new URL(req.url || "", "http://localhost");
5397
5492
  const targetUrl = url.searchParams.get("url");
5398
5493
  const password = url.searchParams.get("password") || "";
5494
+ const extraTrackingMarkersForRequest = parseTrackingMarkersParam(
5495
+ url.searchParams.get("trackingMarkers")
5496
+ );
5497
+ const trackingMarkersForRequest = mergeTrackingMarkers(
5498
+ extraTrackingMarkersForRequest
5499
+ );
5399
5500
  const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
5400
5501
  const proxyParam = (url.searchParams.get("proxy") || "").toLowerCase();
5401
5502
  const useScraperProxy = proxyParam === "1" || proxyParam === "true" || proxyParam === "yes";
@@ -5544,6 +5645,7 @@ function createVisualEditorMiddleware(options) {
5544
5645
  res.end(JSON.stringify({ error: "Password authentication failed." }));
5545
5646
  return;
5546
5647
  }
5648
+ html = stripTrackingScriptsFromScrapedHtml(html, trackingMarkersForRequest);
5547
5649
  html = html.replace(/(href|src|action)="\/(?!\/)/g, `$1="${origin}/`);
5548
5650
  const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5549
5651
  const proxyBase = `/api/conversion-proxy?password=${encodeURIComponent(password)}&url=`;
@@ -5590,8 +5692,8 @@ window.__EDITOR_MODE__=true;
5590
5692
  window.CONVERSION_DISABLE_TRACKING=true;
5591
5693
  window.SNOWPLOW_ENABLED=false;
5592
5694
  var TARGET_HOSTNAME=(function(){try{return new URL(TARGET_ORIGIN).hostname.toLowerCase();}catch(_){return "";}})();
5593
- var TRACKING_HOST_MARKERS=["snowplow","snowplowanalytics","collector","analytics","conversion","taboola"];
5594
- var TRACKING_PATH_MARKERS=["/i","/com.snowplowanalytics.snowplow/","/tp2","/track","/events","/unip"];
5695
+ var TRACKING_HOST_MARKERS=["snowplow","snowplowanalytics","collector","analytics","conversion","taboola","northbeam"];
5696
+ var TRACKING_PATH_MARKERS=["/i","/com.snowplowanalytics.snowplow/","/tp2","/track","/events","/unip","/nb-collector"];
5595
5697
  function hasMarker(value,markers){
5596
5698
  var text=String(value||"").toLowerCase();
5597
5699
  for(var i=0;i<markers.length;i++){
@@ -5635,11 +5737,12 @@ function shouldBlockEditorTracking(rawUrl){
5635
5737
  var isSnowplowStylePath=path==="/i"||path.indexOf("/com.snowplowanalytics.snowplow/")!==-1||path.indexOf("/tp2")!==-1;
5636
5738
  var isTaboolaUnip=host==="trc-events.taboola.com"&&//log/d+/unip(?:/|$)/.test(path);
5637
5739
  var isCollectApiPath=path==="/api/collect"||path.indexOf("/api/collect/")===0;
5638
- return isCrossOriginCollector||(looksLikeHeartbeatPayload&&isSnowplowStylePath)||isCollectApiPath||isTaboolaUnip;
5740
+ var isNbCollectorPath=path==="/nb-collector"||path.indexOf("/nb-collector/")===0;
5741
+ return isCrossOriginCollector||(looksLikeHeartbeatPayload&&isSnowplowStylePath)||isCollectApiPath||isTaboolaUnip||isNbCollectorPath;
5639
5742
  }catch(_){
5640
5743
  try{
5641
5744
  var s=String(rawUrl||"").toLowerCase();
5642
- return s.indexOf("snowplow")!==-1||s.indexOf("com.snowplowanalytics")!==-1||s.indexOf("collector")!==-1||s.indexOf("/api/collect")!==-1||s.indexOf("trc-events.taboola.com")!==-1;
5745
+ return s.indexOf("snowplow")!==-1||s.indexOf("com.snowplowanalytics")!==-1||s.indexOf("collector")!==-1||s.indexOf("/api/collect")!==-1||s.indexOf("trc-events.taboola.com")!==-1||s.indexOf("/nb-collector")!==-1||s.indexOf("northbeam")!==-1;
5643
5746
  }catch(__){
5644
5747
  return false;
5645
5748
  }
package/dist/vite.js CHANGED
@@ -17,6 +17,94 @@ var SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED_RAW = process.env.SCRAPERAPI_REQUEST
17
17
  var SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED = !["0", "false", "no"].includes(
18
18
  SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED_RAW.toLowerCase()
19
19
  );
20
+ var DEFAULT_TRACKING_MARKERS = [
21
+ "snowplow",
22
+ "taboola",
23
+ "googletagmanager",
24
+ "google-analytics",
25
+ "googleads",
26
+ "doubleclick",
27
+ "gtag(",
28
+ "ga(",
29
+ "fbq(",
30
+ "clarity",
31
+ "hotjar",
32
+ "segment.com",
33
+ "mixpanel",
34
+ "amplitude",
35
+ "fullstory",
36
+ "northbeam",
37
+ "nb-collector",
38
+ "/api/collect",
39
+ "/nb-collector",
40
+ '"r":"periodic"',
41
+ '"r": "periodic"'
42
+ ];
43
+ function normalizeTrackingMarkers(input) {
44
+ if (!Array.isArray(input)) return [];
45
+ const deduped = /* @__PURE__ */ new Set();
46
+ const aliases = {
47
+ tabola: "taboola"
48
+ };
49
+ for (let i = 0; i < input.length; i += 1) {
50
+ const raw = input[i];
51
+ if (typeof raw !== "string") continue;
52
+ const marker = raw.trim().toLowerCase();
53
+ if (!marker) continue;
54
+ deduped.add(aliases[marker] || marker);
55
+ }
56
+ return Array.from(deduped);
57
+ }
58
+ function mergeTrackingMarkers(extraMarkers) {
59
+ return normalizeTrackingMarkers([
60
+ ...DEFAULT_TRACKING_MARKERS,
61
+ ...normalizeTrackingMarkers(extraMarkers)
62
+ ]);
63
+ }
64
+ function parseTrackingMarkersParam(raw) {
65
+ if (!raw) return [];
66
+ try {
67
+ return normalizeTrackingMarkers(JSON.parse(raw));
68
+ } catch (_) {
69
+ return normalizeTrackingMarkers(
70
+ raw.split(",").map((v) => v.trim()).filter(Boolean)
71
+ );
72
+ }
73
+ }
74
+ function hasTrackingMarker(input, markers) {
75
+ const text = String(input || "").toLowerCase();
76
+ for (let i = 0; i < markers.length; i += 1) {
77
+ if (text.includes(markers[i])) return true;
78
+ }
79
+ return false;
80
+ }
81
+ function stripTrackingScriptsFromScrapedHtml(html, markers) {
82
+ let removedCount = 0;
83
+ let out = html;
84
+ out = out.replace(/<script\b[\s\S]*?<\/script>/gi, (tag) => {
85
+ const srcMatch = tag.match(/\bsrc\s*=\s*(["'])(.*?)\1/i);
86
+ const src = srcMatch?.[2] || "";
87
+ if (hasTrackingMarker(src, markers) || hasTrackingMarker(tag, markers)) {
88
+ removedCount += 1;
89
+ return "";
90
+ }
91
+ return tag;
92
+ });
93
+ out = out.replace(/<noscript\b[\s\S]*?<\/noscript>/gi, (tag) => {
94
+ if (!hasTrackingMarker(tag, markers)) return tag;
95
+ removedCount += 1;
96
+ return "";
97
+ });
98
+ if (removedCount > 0) {
99
+ out = out.replace(
100
+ /<head([^>]*)>/i,
101
+ `<head$1>
102
+ <meta name="conversion-editor-tracking-scripts-stripped" content="${removedCount}">
103
+ `
104
+ );
105
+ }
106
+ return out;
107
+ }
20
108
  var scraperProxyClientPromise = null;
21
109
  async function getScraperProxyClient() {
22
110
  if (scraperProxyClientPromise) return scraperProxyClientPromise;
@@ -2301,9 +2389,16 @@ function handleLoadExperiment(data) {
2301
2389
  lastLoadedProxyUrl = '';
2302
2390
  return;
2303
2391
  }
2392
+ var extraTrackingMarkers = Array.isArray(data && data.trackingMarkers)
2393
+ ? data.trackingMarkers.filter(function(m){return typeof m === 'string' && m.trim().length > 0;})
2394
+ : [];
2395
+ var trackingMarkersParam = extraTrackingMarkers.length
2396
+ ? '&trackingMarkers=' + encodeURIComponent(JSON.stringify(extraTrackingMarkers))
2397
+ : '';
2304
2398
  var proxyUrl = '/api/conversion-proxy?password=' + encodeURIComponent(data.editorPassword || '') +
2305
2399
  '&url=' + encodeURIComponent(pageUrl) +
2306
- '&strictObserverFreeze=' + encodeURIComponent(data && data.strictObserverFreeze ? '1' : '0');
2400
+ '&strictObserverFreeze=' + encodeURIComponent(data && data.strictObserverFreeze ? '1' : '0') +
2401
+ trackingMarkersParam;
2307
2402
 
2308
2403
  // Parent often re-posts load-experiment when React re-renders (new object identity) or
2309
2404
  // after mutations-changed. Reloading the iframe again wipes variant changesets mid-session.
@@ -5388,6 +5483,12 @@ function createVisualEditorMiddleware(options) {
5388
5483
  const url = new URL(req.url || "", "http://localhost");
5389
5484
  const targetUrl = url.searchParams.get("url");
5390
5485
  const password = url.searchParams.get("password") || "";
5486
+ const extraTrackingMarkersForRequest = parseTrackingMarkersParam(
5487
+ url.searchParams.get("trackingMarkers")
5488
+ );
5489
+ const trackingMarkersForRequest = mergeTrackingMarkers(
5490
+ extraTrackingMarkersForRequest
5491
+ );
5391
5492
  const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
5392
5493
  const proxyParam = (url.searchParams.get("proxy") || "").toLowerCase();
5393
5494
  const useScraperProxy = proxyParam === "1" || proxyParam === "true" || proxyParam === "yes";
@@ -5536,6 +5637,7 @@ function createVisualEditorMiddleware(options) {
5536
5637
  res.end(JSON.stringify({ error: "Password authentication failed." }));
5537
5638
  return;
5538
5639
  }
5640
+ html = stripTrackingScriptsFromScrapedHtml(html, trackingMarkersForRequest);
5539
5641
  html = html.replace(/(href|src|action)="\/(?!\/)/g, `$1="${origin}/`);
5540
5642
  const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5541
5643
  const proxyBase = `/api/conversion-proxy?password=${encodeURIComponent(password)}&url=`;
@@ -5582,8 +5684,8 @@ window.__EDITOR_MODE__=true;
5582
5684
  window.CONVERSION_DISABLE_TRACKING=true;
5583
5685
  window.SNOWPLOW_ENABLED=false;
5584
5686
  var TARGET_HOSTNAME=(function(){try{return new URL(TARGET_ORIGIN).hostname.toLowerCase();}catch(_){return "";}})();
5585
- var TRACKING_HOST_MARKERS=["snowplow","snowplowanalytics","collector","analytics","conversion","taboola"];
5586
- var TRACKING_PATH_MARKERS=["/i","/com.snowplowanalytics.snowplow/","/tp2","/track","/events","/unip"];
5687
+ var TRACKING_HOST_MARKERS=["snowplow","snowplowanalytics","collector","analytics","conversion","taboola","northbeam"];
5688
+ var TRACKING_PATH_MARKERS=["/i","/com.snowplowanalytics.snowplow/","/tp2","/track","/events","/unip","/nb-collector"];
5587
5689
  function hasMarker(value,markers){
5588
5690
  var text=String(value||"").toLowerCase();
5589
5691
  for(var i=0;i<markers.length;i++){
@@ -5627,11 +5729,12 @@ function shouldBlockEditorTracking(rawUrl){
5627
5729
  var isSnowplowStylePath=path==="/i"||path.indexOf("/com.snowplowanalytics.snowplow/")!==-1||path.indexOf("/tp2")!==-1;
5628
5730
  var isTaboolaUnip=host==="trc-events.taboola.com"&&//log/d+/unip(?:/|$)/.test(path);
5629
5731
  var isCollectApiPath=path==="/api/collect"||path.indexOf("/api/collect/")===0;
5630
- return isCrossOriginCollector||(looksLikeHeartbeatPayload&&isSnowplowStylePath)||isCollectApiPath||isTaboolaUnip;
5732
+ var isNbCollectorPath=path==="/nb-collector"||path.indexOf("/nb-collector/")===0;
5733
+ return isCrossOriginCollector||(looksLikeHeartbeatPayload&&isSnowplowStylePath)||isCollectApiPath||isTaboolaUnip||isNbCollectorPath;
5631
5734
  }catch(_){
5632
5735
  try{
5633
5736
  var s=String(rawUrl||"").toLowerCase();
5634
- return s.indexOf("snowplow")!==-1||s.indexOf("com.snowplowanalytics")!==-1||s.indexOf("collector")!==-1||s.indexOf("/api/collect")!==-1||s.indexOf("trc-events.taboola.com")!==-1;
5737
+ return s.indexOf("snowplow")!==-1||s.indexOf("com.snowplowanalytics")!==-1||s.indexOf("collector")!==-1||s.indexOf("/api/collect")!==-1||s.indexOf("trc-events.taboola.com")!==-1||s.indexOf("/nb-collector")!==-1||s.indexOf("northbeam")!==-1;
5635
5738
  }catch(__){
5636
5739
  return false;
5637
5740
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@accelerated-agency/visual-editor",
3
- "version": "0.3.8",
3
+ "version": "0.4.0",
4
4
  "private": false,
5
5
  "description": "Conversion visual editor as a reusable React package",
6
6
  "type": "module",