@accelerated-agency/visual-editor 0.3.8 → 0.3.9

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,91 @@ 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
+ "/api/collect",
45
+ '"r":"periodic"',
46
+ '"r": "periodic"'
47
+ ];
48
+ function normalizeTrackingMarkers(input) {
49
+ if (!Array.isArray(input)) return [];
50
+ const deduped = /* @__PURE__ */ new Set();
51
+ const aliases = {
52
+ tabola: "taboola"
53
+ };
54
+ for (let i = 0; i < input.length; i += 1) {
55
+ const raw = input[i];
56
+ if (typeof raw !== "string") continue;
57
+ const marker = raw.trim().toLowerCase();
58
+ if (!marker) continue;
59
+ deduped.add(aliases[marker] || marker);
60
+ }
61
+ return Array.from(deduped);
62
+ }
63
+ function mergeTrackingMarkers(extraMarkers) {
64
+ return normalizeTrackingMarkers([
65
+ ...DEFAULT_TRACKING_MARKERS,
66
+ ...normalizeTrackingMarkers(extraMarkers)
67
+ ]);
68
+ }
69
+ function parseTrackingMarkersParam(raw) {
70
+ if (!raw) return [];
71
+ try {
72
+ return normalizeTrackingMarkers(JSON.parse(raw));
73
+ } catch (_) {
74
+ return normalizeTrackingMarkers(
75
+ raw.split(",").map((v) => v.trim()).filter(Boolean)
76
+ );
77
+ }
78
+ }
79
+ function hasTrackingMarker(input, markers) {
80
+ const text = String(input || "").toLowerCase();
81
+ for (let i = 0; i < markers.length; i += 1) {
82
+ if (text.includes(markers[i])) return true;
83
+ }
84
+ return false;
85
+ }
86
+ function stripTrackingScriptsFromScrapedHtml(html, markers) {
87
+ let removedCount = 0;
88
+ let out = html;
89
+ out = out.replace(/<script\b[\s\S]*?<\/script>/gi, (tag) => {
90
+ const srcMatch = tag.match(/\bsrc\s*=\s*(["'])(.*?)\1/i);
91
+ const src = srcMatch?.[2] || "";
92
+ if (hasTrackingMarker(src, markers) || hasTrackingMarker(tag, markers)) {
93
+ removedCount += 1;
94
+ return "";
95
+ }
96
+ return tag;
97
+ });
98
+ out = out.replace(/<noscript\b[\s\S]*?<\/noscript>/gi, (tag) => {
99
+ if (!hasTrackingMarker(tag, markers)) return tag;
100
+ removedCount += 1;
101
+ return "";
102
+ });
103
+ if (removedCount > 0) {
104
+ out = out.replace(
105
+ /<head([^>]*)>/i,
106
+ `<head$1>
107
+ <meta name="conversion-editor-tracking-scripts-stripped" content="${removedCount}">
108
+ `
109
+ );
110
+ }
111
+ return out;
112
+ }
28
113
  var scraperProxyClientPromise = null;
29
114
  async function getScraperProxyClient() {
30
115
  if (scraperProxyClientPromise) return scraperProxyClientPromise;
@@ -2309,9 +2394,16 @@ function handleLoadExperiment(data) {
2309
2394
  lastLoadedProxyUrl = '';
2310
2395
  return;
2311
2396
  }
2397
+ var extraTrackingMarkers = Array.isArray(data && data.trackingMarkers)
2398
+ ? data.trackingMarkers.filter(function(m){return typeof m === 'string' && m.trim().length > 0;})
2399
+ : [];
2400
+ var trackingMarkersParam = extraTrackingMarkers.length
2401
+ ? '&trackingMarkers=' + encodeURIComponent(JSON.stringify(extraTrackingMarkers))
2402
+ : '';
2312
2403
  var proxyUrl = '/api/conversion-proxy?password=' + encodeURIComponent(data.editorPassword || '') +
2313
2404
  '&url=' + encodeURIComponent(pageUrl) +
2314
- '&strictObserverFreeze=' + encodeURIComponent(data && data.strictObserverFreeze ? '1' : '0');
2405
+ '&strictObserverFreeze=' + encodeURIComponent(data && data.strictObserverFreeze ? '1' : '0') +
2406
+ trackingMarkersParam;
2315
2407
 
2316
2408
  // Parent often re-posts load-experiment when React re-renders (new object identity) or
2317
2409
  // after mutations-changed. Reloading the iframe again wipes variant changesets mid-session.
@@ -5396,6 +5488,12 @@ function createVisualEditorMiddleware(options) {
5396
5488
  const url = new URL(req.url || "", "http://localhost");
5397
5489
  const targetUrl = url.searchParams.get("url");
5398
5490
  const password = url.searchParams.get("password") || "";
5491
+ const extraTrackingMarkersForRequest = parseTrackingMarkersParam(
5492
+ url.searchParams.get("trackingMarkers")
5493
+ );
5494
+ const trackingMarkersForRequest = mergeTrackingMarkers(
5495
+ extraTrackingMarkersForRequest
5496
+ );
5399
5497
  const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
5400
5498
  const proxyParam = (url.searchParams.get("proxy") || "").toLowerCase();
5401
5499
  const useScraperProxy = proxyParam === "1" || proxyParam === "true" || proxyParam === "yes";
@@ -5544,6 +5642,7 @@ function createVisualEditorMiddleware(options) {
5544
5642
  res.end(JSON.stringify({ error: "Password authentication failed." }));
5545
5643
  return;
5546
5644
  }
5645
+ html = stripTrackingScriptsFromScrapedHtml(html, trackingMarkersForRequest);
5547
5646
  html = html.replace(/(href|src|action)="\/(?!\/)/g, `$1="${origin}/`);
5548
5647
  const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5549
5648
  const proxyBase = `/api/conversion-proxy?password=${encodeURIComponent(password)}&url=`;
package/dist/vite.js CHANGED
@@ -17,6 +17,91 @@ 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
+ "/api/collect",
37
+ '"r":"periodic"',
38
+ '"r": "periodic"'
39
+ ];
40
+ function normalizeTrackingMarkers(input) {
41
+ if (!Array.isArray(input)) return [];
42
+ const deduped = /* @__PURE__ */ new Set();
43
+ const aliases = {
44
+ tabola: "taboola"
45
+ };
46
+ for (let i = 0; i < input.length; i += 1) {
47
+ const raw = input[i];
48
+ if (typeof raw !== "string") continue;
49
+ const marker = raw.trim().toLowerCase();
50
+ if (!marker) continue;
51
+ deduped.add(aliases[marker] || marker);
52
+ }
53
+ return Array.from(deduped);
54
+ }
55
+ function mergeTrackingMarkers(extraMarkers) {
56
+ return normalizeTrackingMarkers([
57
+ ...DEFAULT_TRACKING_MARKERS,
58
+ ...normalizeTrackingMarkers(extraMarkers)
59
+ ]);
60
+ }
61
+ function parseTrackingMarkersParam(raw) {
62
+ if (!raw) return [];
63
+ try {
64
+ return normalizeTrackingMarkers(JSON.parse(raw));
65
+ } catch (_) {
66
+ return normalizeTrackingMarkers(
67
+ raw.split(",").map((v) => v.trim()).filter(Boolean)
68
+ );
69
+ }
70
+ }
71
+ function hasTrackingMarker(input, markers) {
72
+ const text = String(input || "").toLowerCase();
73
+ for (let i = 0; i < markers.length; i += 1) {
74
+ if (text.includes(markers[i])) return true;
75
+ }
76
+ return false;
77
+ }
78
+ function stripTrackingScriptsFromScrapedHtml(html, markers) {
79
+ let removedCount = 0;
80
+ let out = html;
81
+ out = out.replace(/<script\b[\s\S]*?<\/script>/gi, (tag) => {
82
+ const srcMatch = tag.match(/\bsrc\s*=\s*(["'])(.*?)\1/i);
83
+ const src = srcMatch?.[2] || "";
84
+ if (hasTrackingMarker(src, markers) || hasTrackingMarker(tag, markers)) {
85
+ removedCount += 1;
86
+ return "";
87
+ }
88
+ return tag;
89
+ });
90
+ out = out.replace(/<noscript\b[\s\S]*?<\/noscript>/gi, (tag) => {
91
+ if (!hasTrackingMarker(tag, markers)) return tag;
92
+ removedCount += 1;
93
+ return "";
94
+ });
95
+ if (removedCount > 0) {
96
+ out = out.replace(
97
+ /<head([^>]*)>/i,
98
+ `<head$1>
99
+ <meta name="conversion-editor-tracking-scripts-stripped" content="${removedCount}">
100
+ `
101
+ );
102
+ }
103
+ return out;
104
+ }
20
105
  var scraperProxyClientPromise = null;
21
106
  async function getScraperProxyClient() {
22
107
  if (scraperProxyClientPromise) return scraperProxyClientPromise;
@@ -2301,9 +2386,16 @@ function handleLoadExperiment(data) {
2301
2386
  lastLoadedProxyUrl = '';
2302
2387
  return;
2303
2388
  }
2389
+ var extraTrackingMarkers = Array.isArray(data && data.trackingMarkers)
2390
+ ? data.trackingMarkers.filter(function(m){return typeof m === 'string' && m.trim().length > 0;})
2391
+ : [];
2392
+ var trackingMarkersParam = extraTrackingMarkers.length
2393
+ ? '&trackingMarkers=' + encodeURIComponent(JSON.stringify(extraTrackingMarkers))
2394
+ : '';
2304
2395
  var proxyUrl = '/api/conversion-proxy?password=' + encodeURIComponent(data.editorPassword || '') +
2305
2396
  '&url=' + encodeURIComponent(pageUrl) +
2306
- '&strictObserverFreeze=' + encodeURIComponent(data && data.strictObserverFreeze ? '1' : '0');
2397
+ '&strictObserverFreeze=' + encodeURIComponent(data && data.strictObserverFreeze ? '1' : '0') +
2398
+ trackingMarkersParam;
2307
2399
 
2308
2400
  // Parent often re-posts load-experiment when React re-renders (new object identity) or
2309
2401
  // after mutations-changed. Reloading the iframe again wipes variant changesets mid-session.
@@ -5388,6 +5480,12 @@ function createVisualEditorMiddleware(options) {
5388
5480
  const url = new URL(req.url || "", "http://localhost");
5389
5481
  const targetUrl = url.searchParams.get("url");
5390
5482
  const password = url.searchParams.get("password") || "";
5483
+ const extraTrackingMarkersForRequest = parseTrackingMarkersParam(
5484
+ url.searchParams.get("trackingMarkers")
5485
+ );
5486
+ const trackingMarkersForRequest = mergeTrackingMarkers(
5487
+ extraTrackingMarkersForRequest
5488
+ );
5391
5489
  const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
5392
5490
  const proxyParam = (url.searchParams.get("proxy") || "").toLowerCase();
5393
5491
  const useScraperProxy = proxyParam === "1" || proxyParam === "true" || proxyParam === "yes";
@@ -5536,6 +5634,7 @@ function createVisualEditorMiddleware(options) {
5536
5634
  res.end(JSON.stringify({ error: "Password authentication failed." }));
5537
5635
  return;
5538
5636
  }
5637
+ html = stripTrackingScriptsFromScrapedHtml(html, trackingMarkersForRequest);
5539
5638
  html = html.replace(/(href|src|action)="\/(?!\/)/g, `$1="${origin}/`);
5540
5639
  const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5541
5640
  const proxyBase = `/api/conversion-proxy?password=${encodeURIComponent(password)}&url=`;
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.3.9",
4
4
  "private": false,
5
5
  "description": "Conversion visual editor as a reusable React package",
6
6
  "type": "module",