@accelerated-agency/visual-editor 0.3.5 → 0.3.8

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
@@ -4827,6 +4827,7 @@ function PlatformVisualEditorV2({
4827
4827
  onTabChange,
4828
4828
  onDirtyChange,
4829
4829
  onEditorReady,
4830
+ onEditorUrlChanged,
4830
4831
  onSaveSuccess,
4831
4832
  onSaveError,
4832
4833
  onRequestSave,
@@ -4908,6 +4909,9 @@ function PlatformVisualEditorV2({
4908
4909
  setDirty(!!payload?.dirty);
4909
4910
  if (!payload?.dirty) mutationSkipCountRef.current = 0;
4910
4911
  break;
4912
+ case "editor-url-changed":
4913
+ await onEditorUrlChanged?.(payload ?? {});
4914
+ break;
4911
4915
  case "save-experiment":
4912
4916
  if (!onRequestSave) return;
4913
4917
  try {
@@ -4948,6 +4952,7 @@ function PlatformVisualEditorV2({
4948
4952
  loadPayload,
4949
4953
  saveDebounceSkips,
4950
4954
  onEditorReady,
4955
+ onEditorUrlChanged,
4951
4956
  onRequestSave,
4952
4957
  onSaveSuccess,
4953
4958
  onSaveError,
package/dist/vite.cjs CHANGED
@@ -11,6 +11,42 @@ var fs__default = /*#__PURE__*/_interopDefault(fs);
11
11
  var path__default = /*#__PURE__*/_interopDefault(path);
12
12
 
13
13
  // src/visualEditorProxyPlugin.ts
14
+ var SCRAPER_PROXY_HOST = process.env.SCRAPERAPI_PROXY_HOST || "proxy-server.scraperapi.com";
15
+ var SCRAPER_PROXY_PORT = Number(process.env.SCRAPERAPI_PROXY_PORT || "8001");
16
+ var SCRAPER_PROXY_USERNAME_BASE = process.env.SCRAPERAPI_PROXY_USERNAME_BASE || "scraperapi";
17
+ var SCRAPER_PROXY_USERNAME_PARAMS = process.env.SCRAPERAPI_PROXY_USERNAME_PARAMS || "render=true.wait_for_selector=body.follow_redirect=false.keep_headers=true";
18
+ var SCRAPER_PROXY_USERNAME = process.env.SCRAPERAPI_PROXY_USERNAME || [
19
+ SCRAPER_PROXY_USERNAME_BASE,
20
+ SCRAPER_PROXY_USERNAME_PARAMS
21
+ ].filter(Boolean).join(".");
22
+ var SCRAPER_PROXY_PASSWORD = process.env.SCRAPERAPI_PROXY_PASSWORD || process.env.SCRAPERAPI_API_KEY || "e0252333bde7cbf61d2d388e8c4a962a";
23
+ var SCRAPER_API_ENDPOINT = process.env.SCRAPERAPI_ENDPOINT || "https://api.scraperapi.com/";
24
+ var SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED_RAW = process.env.SCRAPERAPI_REQUEST_TLS_REJECT_UNAUTHORIZED || "false";
25
+ var SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED = !["0", "false", "no"].includes(
26
+ SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED_RAW.toLowerCase()
27
+ );
28
+ var scraperProxyClientPromise = null;
29
+ async function getScraperProxyClient() {
30
+ if (scraperProxyClientPromise) return scraperProxyClientPromise;
31
+ scraperProxyClientPromise = (async () => {
32
+ try {
33
+ const undici = await import('undici');
34
+ const proxyUrl = "http://" + encodeURIComponent(SCRAPER_PROXY_USERNAME) + ":" + encodeURIComponent(SCRAPER_PROXY_PASSWORD) + "@" + SCRAPER_PROXY_HOST + ":" + String(SCRAPER_PROXY_PORT);
35
+ return {
36
+ dispatcher: new undici.ProxyAgent({
37
+ uri: proxyUrl,
38
+ requestTls: {
39
+ rejectUnauthorized: SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED
40
+ }
41
+ }),
42
+ fetchFn: undici.fetch
43
+ };
44
+ } catch (_) {
45
+ return null;
46
+ }
47
+ })();
48
+ return scraperProxyClientPromise;
49
+ }
14
50
  var iframeAlwaysShowCss = `<style id="__ce_force_show">#CybotCookiebotDialog,#CybotCookiebotDialogBodyUnderlay,#onetrust-consent-sdk,#onetrust-banner-sdk,.cc-window,.cc-banner,.cc-overlay,#cookie-notice,#cookie-banner,#cookie-consent,.cookie-notice,.cookie-banner,.cookie-consent,.cookie-popup,.cookie-bar,.cookie-message,.cookie-alert,.gdpr-banner,.gdpr-consent,.gdpr-popup,.gdpr-overlay,#gdpr-consent,#gdpr-banner,.consent-banner,.consent-popup,.consent-overlay,#consent-banner,#consent-popup,[class*="cookie-consent"],[class*="cookie-banner"],[class*="cookie-notice"],[class*="CookieConsent"],[class*="CookieBanner"],[id*="cookie-consent"],[id*="cookie-banner"],[id*="cookie-notice"],[aria-label*="cookie" i],[aria-label*="consent" i],.klaro,.klaro .cookie-modal,#usercentrics-root,.trustarc-banner,#truste-consent-track,#hs-eu-cookie-confirmation,.osano-cm-window,.osano-cm-dialog,.evidon-banner,#_evidon_banner,.js-cookie-consent,.cookie-disclaimer,.shopify-section-cookies,#shopify-section-cookies,#shopify-pc__banner,#shopify-pc__modal,.privacy-banner,.privacy-popup,[data-testid="cookie-banner"],[data-testid="consent-banner"],.amgdprcookie-bar-container,[data-amcookie-js="bar"],.amgdprjs-bar-template,.amgdprcookie-modal-container,.amgdprcookie-modal-overlay,#cmplz-cookiebanner-container,.cmplz-cookiebanner,#iubenda-cs-banner,.iubenda-cs-container,#qc-cmp2-container,.qc-cmp2-consent-info,#didomi-host,.didomi-popup-container,.didomi-notice,#termly-code-snippet-support,[class*="termly"],[class*="gdprcookie"],[class*="amgdpr"],[id*="gdpr-cookie"],[class*="cookie-modal"],[id*="cookie-modal"],[class*="cookieConsent"],[id*="cookieConsent"]{display:revert!important;visibility:visible!important;opacity:1!important;pointer-events:auto!important;height:auto!important;max-height:none!important;overflow:visible!important;}</style>`;
15
51
  var iframeAlwaysShowCssGuardScript = `<script id="__ce_force_show_guard">(function(){try{
16
52
  function ensureForceShowStyleLast(){
@@ -2459,13 +2495,7 @@ function granularAnySelectorMatches(doc, cs) {
2459
2495
 
2460
2496
  /** Bust bfcache / same-URL no-op reloads so the iframe actually re-parses (loading \u2192 interactive). */
2461
2497
  function appendIframeReloadBust(url) {
2462
- if (!url || url === 'about:blank') return url;
2463
- var stamp = Date.now();
2464
- if (url.indexOf('__ve_reload=') !== -1) {
2465
- return url.replace(/([&?])__ve_reload=[0-9]+/, '$1__ve_reload=' + stamp);
2466
- }
2467
- var sep = url.indexOf('?') !== -1 ? '&' : '?';
2468
- return url + sep + '__ve_reload=' + stamp;
2498
+ return url;
2469
2499
  }
2470
2500
 
2471
2501
  // True when the iframe contentDocument belongs to the current iframe.src navigation.
@@ -2485,13 +2515,7 @@ function iframeDocMatchesNavigatedSrc(iframe, doc) {
2485
2515
  try {
2486
2516
  var base = window.location.href;
2487
2517
  var su = new URL(src, base);
2488
- if (su.searchParams && su.searchParams.has('__ve_reload')) {
2489
- su.searchParams.delete('__ve_reload');
2490
- }
2491
2518
  var du = new URL(loc, base);
2492
- if (du.searchParams && du.searchParams.has('__ve_reload')) {
2493
- du.searchParams.delete('__ve_reload');
2494
- }
2495
2519
  // Same-origin proxy that keeps document address aligned with iframe src
2496
2520
  if (su.origin === du.origin && su.pathname + su.search === du.pathname + du.search) {
2497
2521
  return true;
@@ -2621,6 +2645,43 @@ function isIframeDomReady(iframe, doc) {
2621
2645
  return true;
2622
2646
  }
2623
2647
 
2648
+ function parseEditorUrlPayload(rawUrl) {
2649
+ if (!rawUrl) return null;
2650
+ try {
2651
+ var parsed = new URL(String(rawUrl), window.location.href);
2652
+ var nestedUrl = parsed.searchParams.get('url');
2653
+ var nestedPassword = parsed.searchParams.get('password');
2654
+ if (nestedUrl || nestedPassword) {
2655
+ return {
2656
+ url: nestedUrl || undefined,
2657
+ password: nestedPassword || undefined,
2658
+ };
2659
+ }
2660
+ return {
2661
+ url: parsed.toString(),
2662
+ password:
2663
+ (experimentData && experimentData.editorPassword)
2664
+ ? String(experimentData.editorPassword)
2665
+ : undefined,
2666
+ };
2667
+ } catch(_) {
2668
+ return null;
2669
+ }
2670
+ }
2671
+
2672
+ var lastEditorUrlPayloadKey = '';
2673
+ function emitEditorUrlChangedPayload(payload) {
2674
+ if (!payload) return;
2675
+ var key = String(payload.url || '') + '|' + String(payload.password || '');
2676
+ if (key === lastEditorUrlPayloadKey) return;
2677
+ lastEditorUrlPayloadKey = key;
2678
+ send('editor-url-changed', payload);
2679
+ }
2680
+ function emitEditorUrlChanged(rawUrl) {
2681
+ var payload = parseEditorUrlPayload(rawUrl);
2682
+ emitEditorUrlChangedPayload(payload);
2683
+ }
2684
+
2624
2685
  function loadPage(proxyUrl) {
2625
2686
  showNoUrl(false);
2626
2687
  lastLoadedProxyUrl = proxyUrl;
@@ -2630,6 +2691,7 @@ function loadPage(proxyUrl) {
2630
2691
  iframe.style.display = 'block';
2631
2692
  setIframePageLoadingUi(true);
2632
2693
  iframe.src = appendIframeReloadBust(proxyUrl);
2694
+ emitEditorUrlChanged(proxyUrl);
2633
2695
  startIframeContentApplyWatcher(navGen, iframe.contentDocument || null);
2634
2696
  scheduleDomTreeRefresh();
2635
2697
  }
@@ -5048,6 +5110,18 @@ window.addEventListener('load', function() {
5048
5110
 
5049
5111
  // After each iframe load: apply variation, wire click+mutation handlers
5050
5112
  var iframe = document.getElementById('iframeId');
5113
+ window.addEventListener('message', function(ev) {
5114
+ try {
5115
+ var d = ev && ev.data;
5116
+ if (!d || d.channel !== 'vvveb-proxy-url' || d.type !== 'editor-url-changed') return;
5117
+ if (!iframe || !iframe.contentWindow || ev.source !== iframe.contentWindow) return;
5118
+ var payload = d.payload || {};
5119
+ emitEditorUrlChangedPayload({
5120
+ url: payload.url || undefined,
5121
+ password: payload.password || undefined,
5122
+ });
5123
+ } catch(_) {}
5124
+ });
5051
5125
  iframe.addEventListener('load', function() {
5052
5126
  if (!iframe.src || iframe.src === 'about:blank' || iframe.src === window.location.href) return;
5053
5127
  var doc = iframe.contentDocument;
@@ -5058,6 +5132,7 @@ window.addEventListener('load', function() {
5058
5132
  }
5059
5133
  var docUrl = '';
5060
5134
  try { docUrl = String(doc.URL || ''); } catch(_) {}
5135
+ emitEditorUrlChanged(iframe.src || docUrl);
5061
5136
  // Stale events: src may already be the proxy URL while the document is still
5062
5137
  // about:blank (e.g. src cleared then reset to force reload). Ask sync path to retry.
5063
5138
  if (docUrl === 'about:blank') {
@@ -5322,6 +5397,8 @@ function createVisualEditorMiddleware(options) {
5322
5397
  const targetUrl = url.searchParams.get("url");
5323
5398
  const password = url.searchParams.get("password") || "";
5324
5399
  const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
5400
+ const proxyParam = (url.searchParams.get("proxy") || "").toLowerCase();
5401
+ const useScraperProxy = proxyParam === "1" || proxyParam === "true" || proxyParam === "yes";
5325
5402
  const strictObserverFreezeForRequest = strictFreezeParam === "1" || strictFreezeParam === "true" || strictFreezeParam === "yes" ? true : strictFreezeParam === "0" || strictFreezeParam === "false" || strictFreezeParam === "no" ? false : strictObserverFreeze;
5326
5403
  if (!targetUrl) {
5327
5404
  res.statusCode = 400;
@@ -5331,13 +5408,37 @@ function createVisualEditorMiddleware(options) {
5331
5408
  const parsed = new URL(targetUrl);
5332
5409
  const origin = parsed.origin;
5333
5410
  const method = (req.method || "GET").toUpperCase();
5411
+ const scraperProxyClient = useScraperProxy ? await getScraperProxyClient() : null;
5412
+ if (useScraperProxy && !scraperProxyClient) {
5413
+ res.statusCode = 500;
5414
+ res.setHeader("Content-Type", "application/json");
5415
+ res.end(
5416
+ JSON.stringify({
5417
+ error: "ScraperAPI proxy is not configured. Set SCRAPERAPI_PROXY_PASSWORD or SCRAPERAPI_API_KEY."
5418
+ })
5419
+ );
5420
+ return;
5421
+ }
5422
+ if (!SCRAPER_PROXY_PASSWORD) ;
5423
+ const upstreamFetch = (input, init = {}) => {
5424
+ if (!useScraperProxy || !scraperProxyClient) {
5425
+ const scraperUrl = new URL(SCRAPER_API_ENDPOINT);
5426
+ scraperUrl.searchParams.set("api_key", SCRAPER_PROXY_PASSWORD);
5427
+ scraperUrl.searchParams.set("url", input);
5428
+ return fetch(scraperUrl.toString(), init);
5429
+ }
5430
+ return scraperProxyClient.fetchFn(input, {
5431
+ ...init,
5432
+ dispatcher: scraperProxyClient.dispatcher
5433
+ });
5434
+ };
5334
5435
  const headers = {
5335
5436
  "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
5336
5437
  Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
5337
5438
  };
5338
5439
  let cookieHeader = "";
5339
5440
  if (password) {
5340
- const passResp = await fetch(`${origin}/password`, {
5441
+ const passResp = await upstreamFetch(`${origin}/password`, {
5341
5442
  method: "POST",
5342
5443
  headers: {
5343
5444
  "Content-Type": "application/x-www-form-urlencoded",
@@ -5384,7 +5485,7 @@ function createVisualEditorMiddleware(options) {
5384
5485
  const timeoutId = setTimeout(() => ac.abort(), upstreamTimeoutMs);
5385
5486
  let upstream;
5386
5487
  try {
5387
- upstream = await fetch(targetUrl, {
5488
+ upstream = await upstreamFetch(targetUrl, {
5388
5489
  method,
5389
5490
  headers: fetchHeaders,
5390
5491
  body: requestBody ? Buffer.from(requestBody) : null,
@@ -5394,11 +5495,27 @@ function createVisualEditorMiddleware(options) {
5394
5495
  } catch (fetchErr) {
5395
5496
  clearTimeout(timeoutId);
5396
5497
  const aborted = fetchErr?.name === "AbortError";
5498
+ const fetchCause = fetchErr?.cause;
5397
5499
  res.statusCode = aborted ? 504 : 502;
5398
5500
  res.setHeader("Content-Type", "application/json");
5399
5501
  res.end(
5400
5502
  JSON.stringify({
5401
- error: aborted ? `Upstream request timed out after ${upstreamTimeoutMs / 1e3}s` : fetchErr?.message || "Upstream fetch failed"
5503
+ error: aborted ? `Upstream request timed out after ${upstreamTimeoutMs / 1e3}s` : fetchErr?.message || "Upstream fetch failed",
5504
+ phase: useScraperProxy ? "scraperapi-proxy-fetch" : "scraperapi-simple-fetch",
5505
+ fetchMode: useScraperProxy ? "proxy" : "simple",
5506
+ scraperapi: {
5507
+ host: SCRAPER_PROXY_HOST,
5508
+ port: SCRAPER_PROXY_PORT,
5509
+ username: SCRAPER_PROXY_USERNAME,
5510
+ endpoint: SCRAPER_API_ENDPOINT,
5511
+ hasProxyPassword: Boolean(SCRAPER_PROXY_PASSWORD),
5512
+ requestTlsRejectUnauthorized: SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED
5513
+ },
5514
+ cause: fetchCause && typeof fetchCause === "object" ? {
5515
+ name: fetchCause.name,
5516
+ code: fetchCause.code,
5517
+ message: fetchCause.message
5518
+ } : fetchCause ? String(fetchCause) : null
5402
5519
  })
5403
5520
  );
5404
5521
  return;
@@ -5429,7 +5546,7 @@ function createVisualEditorMiddleware(options) {
5429
5546
  }
5430
5547
  html = html.replace(/(href|src|action)="\/(?!\/)/g, `$1="${origin}/`);
5431
5548
  const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5432
- const proxyBase = `/api/conversion-proxy?__ve_reload=${Date.now()}&password=${encodeURIComponent(password)}&url=`;
5549
+ const proxyBase = `/api/conversion-proxy?password=${encodeURIComponent(password)}&url=`;
5433
5550
  html = html.replace(
5434
5551
  new RegExp(`(href|action)="${escapedOrigin}(/[^"]*)"`, "g"),
5435
5552
  (match, attr, urlPath) => {
@@ -5440,6 +5557,12 @@ function createVisualEditorMiddleware(options) {
5440
5557
  return `${attr}="${proxyBase}${encodeURIComponent(origin + urlPath)}"`;
5441
5558
  }
5442
5559
  );
5560
+ html = html.replace(
5561
+ /data-link="\/(?!\/)([^"]*)"/g,
5562
+ (_match, pathPart) => `data-link="/api/conversion-proxy?password=${encodeURIComponent(password)}&url=${encodeURIComponent(
5563
+ `${origin}/${pathPart}`
5564
+ )}"`
5565
+ );
5443
5566
  if (html.includes("</head>")) {
5444
5567
  html = html.replace(
5445
5568
  "</head>",
@@ -5461,10 +5584,125 @@ var TARGET_ORIGIN=${JSON.stringify(origin)};
5461
5584
  var TARGET_PAGE_URL=${JSON.stringify(targetUrl)};
5462
5585
  var PROXY_PASSWORD=${JSON.stringify(password)};
5463
5586
  var STRICT_OBSERVER_FREEZE=${JSON.stringify(strictObserverFreezeForRequest)};
5587
+ var PARENT_URL_CHANNEL="vvveb-proxy-url";
5464
5588
  window.__CONVERSION_EDITOR_ACTIVE__=true;
5589
+ window.__EDITOR_MODE__=true;
5590
+ window.CONVERSION_DISABLE_TRACKING=true;
5591
+ window.SNOWPLOW_ENABLED=false;
5592
+ 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"];
5595
+ function hasMarker(value,markers){
5596
+ var text=String(value||"").toLowerCase();
5597
+ for(var i=0;i<markers.length;i++){
5598
+ if(text.indexOf(markers[i])!==-1) return true;
5599
+ }
5600
+ return false;
5601
+ }
5602
+ function isPeriodicCollectPayload(data){
5603
+ try{
5604
+ if(data==null) return false;
5605
+ if(typeof data==="string"){
5606
+ if(data.indexOf('"r":"periodic"')!==-1||data.indexOf('"r": "periodic"')!==-1) return true;
5607
+ try{
5608
+ var parsed=JSON.parse(data);
5609
+ return !!(parsed&&parsed.r==="periodic");
5610
+ }catch(_){}
5611
+ return false;
5612
+ }
5613
+ if(typeof URLSearchParams!=="undefined"&&data instanceof URLSearchParams){
5614
+ return data.get("r")==="periodic";
5615
+ }
5616
+ if(typeof FormData!=="undefined"&&data instanceof FormData){
5617
+ return data.get("r")==="periodic";
5618
+ }
5619
+ if(typeof data==="object"){
5620
+ return !!(data&&data.r==="periodic");
5621
+ }
5622
+ }catch(_){}
5623
+ return false;
5624
+ }
5625
+ function shouldBlockEditorTracking(rawUrl){
5626
+ try{
5627
+ var u=new URL(String(rawUrl||""),window.location.href);
5628
+ var host=(u.hostname||"").toLowerCase();
5629
+ var path=(u.pathname||"").toLowerCase();
5630
+ var q=u.searchParams;
5631
+ var hasViewportPing=q.has("vp")&&(q.has("pp_miy")||q.has("pp_may"));
5632
+ var hasSessionIds=q.has("sid")||q.has("duid");
5633
+ var looksLikeHeartbeatPayload=hasViewportPing&&hasSessionIds;
5634
+ var isCrossOriginCollector=host!==TARGET_HOSTNAME&&hasMarker(host,TRACKING_HOST_MARKERS)&&hasMarker(path,TRACKING_PATH_MARKERS);
5635
+ var isSnowplowStylePath=path==="/i"||path.indexOf("/com.snowplowanalytics.snowplow/")!==-1||path.indexOf("/tp2")!==-1;
5636
+ var isTaboolaUnip=host==="trc-events.taboola.com"&&//log/d+/unip(?:/|$)/.test(path);
5637
+ var isCollectApiPath=path==="/api/collect"||path.indexOf("/api/collect/")===0;
5638
+ return isCrossOriginCollector||(looksLikeHeartbeatPayload&&isSnowplowStylePath)||isCollectApiPath||isTaboolaUnip;
5639
+ }catch(_){
5640
+ try{
5641
+ 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;
5643
+ }catch(__){
5644
+ return false;
5645
+ }
5646
+ }
5647
+ }
5648
+ try{
5649
+ if(typeof window.snowplow==="function"){
5650
+ try{window.snowplow("disableActivityTracking");}catch(_){}
5651
+ try{window.snowplow("disableAnonymousTracking");}catch(_){}
5652
+ }
5653
+ }catch(_){}
5654
+ try{
5655
+ if(!window.__CONVERSION_TRACKING_GUARD__){
5656
+ window.__CONVERSION_TRACKING_GUARD__=true;
5657
+ if(window.fetch&&typeof window.fetch==="function"){
5658
+ var _trackingFetch=window.fetch.bind(window);
5659
+ window.fetch=function(input,init){
5660
+ try{
5661
+ var raw=typeof input==="string"?input:(input&&input.url?String(input.url):"");
5662
+ var body=init&&Object.prototype.hasOwnProperty.call(init,"body")?init.body:null;
5663
+ var blockCollectPeriodic=raw&&String(raw).indexOf("/api/collect")!==-1&&isPeriodicCollectPayload(body);
5664
+ if(window.__CONVERSION_EDITOR_ACTIVE__&&(shouldBlockEditorTracking(raw)||blockCollectPeriodic)){
5665
+ return Promise.resolve(new Response("",{status:204,statusText:"No Content"}));
5666
+ }
5667
+ }catch(_){}
5668
+ return _trackingFetch(input,init);
5669
+ };
5670
+ }
5671
+ if(window.XMLHttpRequest&&window.XMLHttpRequest.prototype){
5672
+ if(typeof window.XMLHttpRequest.prototype.open==="function"){
5673
+ var _trackingOpen=window.XMLHttpRequest.prototype.open;
5674
+ window.XMLHttpRequest.prototype.open=function(method,url){
5675
+ try{
5676
+ if(window.__CONVERSION_EDITOR_ACTIVE__&&shouldBlockEditorTracking(url)){
5677
+ arguments[1]="data:text/plain,{}";
5678
+ }
5679
+ }catch(_){}
5680
+ return _trackingOpen.apply(this,arguments);
5681
+ };
5682
+ }
5683
+ }
5684
+ if(window.navigator&&typeof window.navigator.sendBeacon==="function"){
5685
+ var _trackingBeacon=window.navigator.sendBeacon.bind(window.navigator);
5686
+ window.navigator.sendBeacon=function(url,data){
5687
+ try{
5688
+ var blockCollectPeriodic=url&&String(url).indexOf("/api/collect")!==-1&&isPeriodicCollectPayload(data);
5689
+ if(window.__CONVERSION_EDITOR_ACTIVE__&&(shouldBlockEditorTracking(url)||blockCollectPeriodic)) return true;
5690
+ }catch(_){}
5691
+ return _trackingBeacon(url,data);
5692
+ };
5693
+ }
5694
+ }
5695
+ }catch(_){}
5696
+ function getEditorUrlPayload(){try{var u=new URL(window.location.href);var nested=u.searchParams.get("url");return{url:nested||u.toString(),password:u.searchParams.get("password")||undefined};}catch(_){return null;}}
5697
+ function notifyEditorUrlChanged(){try{var payload=getEditorUrlPayload();if(!payload)return;if(window.parent){window.parent.postMessage({channel:PARENT_URL_CHANNEL,type:"editor-url-changed",payload:payload},"*");}}catch(_){}}
5698
+ try{notifyEditorUrlChanged();}catch(_){}
5699
+ try{if(window.history&&typeof window.history.pushState==="function"){var nativePushState=window.history.pushState;window.history.pushState=function(){var ret=nativePushState.apply(window.history,arguments);setTimeout(notifyEditorUrlChanged,0);return ret;};}}catch(_){}
5700
+ try{if(window.history&&typeof window.history.replaceState==="function"){var nativeReplaceState=window.history.replaceState;window.history.replaceState=function(){var ret=nativeReplaceState.apply(window.history,arguments);setTimeout(notifyEditorUrlChanged,0);return ret;};}}catch(_){}
5701
+ try{window.addEventListener("popstate",notifyEditorUrlChanged,true);}catch(_){}
5702
+ try{window.addEventListener("hashchange",notifyEditorUrlChanged,true);}catch(_){}
5465
5703
  function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
5466
5704
  function toAbsolute(raw){if(isSkippable(raw))return raw;try{var base=raw.startsWith("/")||raw.startsWith("//")?TARGET_ORIGIN:TARGET_PAGE_URL;return new URL(raw,base).toString();}catch(_){return raw;}}
5467
- function toProxy(raw){if(isSkippable(raw))return null;var abs=toAbsolute(raw);if(!abs||typeof abs!=="string")return null;try{var parsed=new URL(abs);if(parsed.origin!==TARGET_ORIGIN)return null;return "/api/conversion-proxy?__ve_reload="+Date.now()+"&password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());}catch(_){return null;}}
5705
+ function toProxy(raw){if(isSkippable(raw))return null;var abs=toAbsolute(raw);if(!abs||typeof abs!=="string")return null;try{var parsed=new URL(abs);if(parsed.origin!==TARGET_ORIGIN)return null;return "/api/conversion-proxy?password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());}catch(_){return null;}}
5468
5706
  var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
5469
5707
  var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
5470
5708
  function safeNavigate(raw,mode){var abs=toAbsolute(raw);var prox=toProxy(raw);if(!prox){try{console.warn("[conversion-proxy] redirect blocked",{mode:mode,requested:raw,resolved:abs,origin:TARGET_ORIGIN});}catch(_){}return false;}try{console.info("[conversion-proxy] redirect intercepted",{mode:mode,requested:raw,resolved:abs,proxied:prox});if(mode==="replace"&&nativeReplace){nativeReplace(prox);return true;}if(nativeAssign){nativeAssign(prox);return true;}window.location.href=prox;return true;}catch(err){try{console.warn("[conversion-proxy] redirect interception failed",{mode:mode,requested:raw,resolved:abs,proxied:prox,error:err&&err.message?err.message:String(err)});}catch(_){}return false;}}
@@ -5545,9 +5783,9 @@ if(window.fetch){
5545
5783
  }
5546
5784
  if(window.XMLHttpRequest&&window.XMLHttpRequest.prototype&&window.XMLHttpRequest.prototype.open){var _open=window.XMLHttpRequest.prototype.open;window.XMLHttpRequest.prototype.open=function(method,url){try{var u=resolveUrl(String(url));if(u&&isNestedMalformedProxy(u)){arguments[1]=EMPTY_JSON_DATA;}else{arguments[1]=toAbsoluteOriginUrl(url);}}catch(_){}return _open.apply(this,arguments);};}
5547
5785
  if(window.navigator&&typeof window.navigator.sendBeacon==="function"){var _beacon=window.navigator.sendBeacon.bind(window.navigator);window.navigator.sendBeacon=function(url,data){try{if(skipNestedProxyNetwork(String(url)))return true;}catch(_){}return _beacon(url,data);};}
5548
- function withReloadBust(urlRaw){try{var u=resolveUrl(String(urlRaw||""));if(!u)return null;var p=u.pathname||"";var isRootProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0;if(!isRootProxyPath)return null;u.searchParams.set("__ve_reload",String(Date.now()));return u.toString();}catch(_){return null;}}
5549
- document.addEventListener("click",function(ev){try{var t=ev&&ev.target;if(!t||!t.closest)return;var a=t.closest("a[href]");if(!a)return;var href=a.getAttribute("href")||a.href;var bust=withReloadBust(href);if(bust)a.setAttribute("href",bust);}catch(_){}},true);
5550
- document.addEventListener("submit",function(ev){try{var f=ev&&ev.target;if(!f||!f.getAttribute)return;var act=f.getAttribute("action")||"";var bust=withReloadBust(act);if(bust)f.setAttribute("action",bust);}catch(_){}},true);
5786
+ function withReloadBust(urlRaw){try{var u=resolveUrl(String(urlRaw||""));if(!u)return null;var p=u.pathname||"";var isRootProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0;if(!isRootProxyPath)return null;return u.toString();}catch(_){return null;}}
5787
+ document.addEventListener("click",function(ev){try{var t=ev&&ev.target;if(!t||!t.closest)return;var a=t.closest("a[href]");if(a){var href=a.getAttribute("href")||a.href||"";var hasModifier=!!(ev.metaKey||ev.ctrlKey||ev.shiftKey||ev.altKey);var targetAttr=(a.getAttribute("target")||"").toLowerCase();var isNewTab=targetAttr==="_blank";var isDownload=!!a.getAttribute("download");if(hasModifier||isNewTab||isDownload)return;var prox=toProxy(href);if(!prox)return;a.setAttribute("href",prox);if(ev&&typeof ev.preventDefault==="function")ev.preventDefault();safeNavigate(href,"assign");return;}var summary=t.closest("summary[data-link]");if(summary&&summary.getAttribute){var raw=summary.getAttribute("data-link")||"";if(raw){var prox2=toProxy(raw);if(prox2){summary.setAttribute("data-link",prox2);if(ev&&typeof ev.preventDefault==="function")ev.preventDefault();safeNavigate(raw,"assign");}}}}catch(_){}},true);
5788
+ document.addEventListener("submit",function(ev){try{var f=ev&&ev.target;if(!f||!f.getAttribute)return;var act=f.getAttribute("action")||window.location.href;var prox=toProxy(act);if(prox)f.setAttribute("action",prox);}catch(_){}},true);
5551
5789
  if(window.navigator&&window.navigator.serviceWorker&&typeof window.navigator.serviceWorker.register==="function"){window.navigator.serviceWorker.register=function(){return Promise.resolve({scope:"disabled-in-editor-proxy"});};}
5552
5790
  }catch(_){}})();</script>`;
5553
5791
  if (html.includes("</head>")) {
package/dist/vite.js CHANGED
@@ -3,6 +3,42 @@ import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
4
 
5
5
  // src/visualEditorProxyPlugin.ts
6
+ var SCRAPER_PROXY_HOST = process.env.SCRAPERAPI_PROXY_HOST || "proxy-server.scraperapi.com";
7
+ var SCRAPER_PROXY_PORT = Number(process.env.SCRAPERAPI_PROXY_PORT || "8001");
8
+ var SCRAPER_PROXY_USERNAME_BASE = process.env.SCRAPERAPI_PROXY_USERNAME_BASE || "scraperapi";
9
+ var SCRAPER_PROXY_USERNAME_PARAMS = process.env.SCRAPERAPI_PROXY_USERNAME_PARAMS || "render=true.wait_for_selector=body.follow_redirect=false.keep_headers=true";
10
+ var SCRAPER_PROXY_USERNAME = process.env.SCRAPERAPI_PROXY_USERNAME || [
11
+ SCRAPER_PROXY_USERNAME_BASE,
12
+ SCRAPER_PROXY_USERNAME_PARAMS
13
+ ].filter(Boolean).join(".");
14
+ var SCRAPER_PROXY_PASSWORD = process.env.SCRAPERAPI_PROXY_PASSWORD || process.env.SCRAPERAPI_API_KEY || "e0252333bde7cbf61d2d388e8c4a962a";
15
+ var SCRAPER_API_ENDPOINT = process.env.SCRAPERAPI_ENDPOINT || "https://api.scraperapi.com/";
16
+ var SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED_RAW = process.env.SCRAPERAPI_REQUEST_TLS_REJECT_UNAUTHORIZED || "false";
17
+ var SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED = !["0", "false", "no"].includes(
18
+ SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED_RAW.toLowerCase()
19
+ );
20
+ var scraperProxyClientPromise = null;
21
+ async function getScraperProxyClient() {
22
+ if (scraperProxyClientPromise) return scraperProxyClientPromise;
23
+ scraperProxyClientPromise = (async () => {
24
+ try {
25
+ const undici = await import('undici');
26
+ const proxyUrl = "http://" + encodeURIComponent(SCRAPER_PROXY_USERNAME) + ":" + encodeURIComponent(SCRAPER_PROXY_PASSWORD) + "@" + SCRAPER_PROXY_HOST + ":" + String(SCRAPER_PROXY_PORT);
27
+ return {
28
+ dispatcher: new undici.ProxyAgent({
29
+ uri: proxyUrl,
30
+ requestTls: {
31
+ rejectUnauthorized: SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED
32
+ }
33
+ }),
34
+ fetchFn: undici.fetch
35
+ };
36
+ } catch (_) {
37
+ return null;
38
+ }
39
+ })();
40
+ return scraperProxyClientPromise;
41
+ }
6
42
  var iframeAlwaysShowCss = `<style id="__ce_force_show">#CybotCookiebotDialog,#CybotCookiebotDialogBodyUnderlay,#onetrust-consent-sdk,#onetrust-banner-sdk,.cc-window,.cc-banner,.cc-overlay,#cookie-notice,#cookie-banner,#cookie-consent,.cookie-notice,.cookie-banner,.cookie-consent,.cookie-popup,.cookie-bar,.cookie-message,.cookie-alert,.gdpr-banner,.gdpr-consent,.gdpr-popup,.gdpr-overlay,#gdpr-consent,#gdpr-banner,.consent-banner,.consent-popup,.consent-overlay,#consent-banner,#consent-popup,[class*="cookie-consent"],[class*="cookie-banner"],[class*="cookie-notice"],[class*="CookieConsent"],[class*="CookieBanner"],[id*="cookie-consent"],[id*="cookie-banner"],[id*="cookie-notice"],[aria-label*="cookie" i],[aria-label*="consent" i],.klaro,.klaro .cookie-modal,#usercentrics-root,.trustarc-banner,#truste-consent-track,#hs-eu-cookie-confirmation,.osano-cm-window,.osano-cm-dialog,.evidon-banner,#_evidon_banner,.js-cookie-consent,.cookie-disclaimer,.shopify-section-cookies,#shopify-section-cookies,#shopify-pc__banner,#shopify-pc__modal,.privacy-banner,.privacy-popup,[data-testid="cookie-banner"],[data-testid="consent-banner"],.amgdprcookie-bar-container,[data-amcookie-js="bar"],.amgdprjs-bar-template,.amgdprcookie-modal-container,.amgdprcookie-modal-overlay,#cmplz-cookiebanner-container,.cmplz-cookiebanner,#iubenda-cs-banner,.iubenda-cs-container,#qc-cmp2-container,.qc-cmp2-consent-info,#didomi-host,.didomi-popup-container,.didomi-notice,#termly-code-snippet-support,[class*="termly"],[class*="gdprcookie"],[class*="amgdpr"],[id*="gdpr-cookie"],[class*="cookie-modal"],[id*="cookie-modal"],[class*="cookieConsent"],[id*="cookieConsent"]{display:revert!important;visibility:visible!important;opacity:1!important;pointer-events:auto!important;height:auto!important;max-height:none!important;overflow:visible!important;}</style>`;
7
43
  var iframeAlwaysShowCssGuardScript = `<script id="__ce_force_show_guard">(function(){try{
8
44
  function ensureForceShowStyleLast(){
@@ -2451,13 +2487,7 @@ function granularAnySelectorMatches(doc, cs) {
2451
2487
 
2452
2488
  /** Bust bfcache / same-URL no-op reloads so the iframe actually re-parses (loading \u2192 interactive). */
2453
2489
  function appendIframeReloadBust(url) {
2454
- if (!url || url === 'about:blank') return url;
2455
- var stamp = Date.now();
2456
- if (url.indexOf('__ve_reload=') !== -1) {
2457
- return url.replace(/([&?])__ve_reload=[0-9]+/, '$1__ve_reload=' + stamp);
2458
- }
2459
- var sep = url.indexOf('?') !== -1 ? '&' : '?';
2460
- return url + sep + '__ve_reload=' + stamp;
2490
+ return url;
2461
2491
  }
2462
2492
 
2463
2493
  // True when the iframe contentDocument belongs to the current iframe.src navigation.
@@ -2477,13 +2507,7 @@ function iframeDocMatchesNavigatedSrc(iframe, doc) {
2477
2507
  try {
2478
2508
  var base = window.location.href;
2479
2509
  var su = new URL(src, base);
2480
- if (su.searchParams && su.searchParams.has('__ve_reload')) {
2481
- su.searchParams.delete('__ve_reload');
2482
- }
2483
2510
  var du = new URL(loc, base);
2484
- if (du.searchParams && du.searchParams.has('__ve_reload')) {
2485
- du.searchParams.delete('__ve_reload');
2486
- }
2487
2511
  // Same-origin proxy that keeps document address aligned with iframe src
2488
2512
  if (su.origin === du.origin && su.pathname + su.search === du.pathname + du.search) {
2489
2513
  return true;
@@ -2613,6 +2637,43 @@ function isIframeDomReady(iframe, doc) {
2613
2637
  return true;
2614
2638
  }
2615
2639
 
2640
+ function parseEditorUrlPayload(rawUrl) {
2641
+ if (!rawUrl) return null;
2642
+ try {
2643
+ var parsed = new URL(String(rawUrl), window.location.href);
2644
+ var nestedUrl = parsed.searchParams.get('url');
2645
+ var nestedPassword = parsed.searchParams.get('password');
2646
+ if (nestedUrl || nestedPassword) {
2647
+ return {
2648
+ url: nestedUrl || undefined,
2649
+ password: nestedPassword || undefined,
2650
+ };
2651
+ }
2652
+ return {
2653
+ url: parsed.toString(),
2654
+ password:
2655
+ (experimentData && experimentData.editorPassword)
2656
+ ? String(experimentData.editorPassword)
2657
+ : undefined,
2658
+ };
2659
+ } catch(_) {
2660
+ return null;
2661
+ }
2662
+ }
2663
+
2664
+ var lastEditorUrlPayloadKey = '';
2665
+ function emitEditorUrlChangedPayload(payload) {
2666
+ if (!payload) return;
2667
+ var key = String(payload.url || '') + '|' + String(payload.password || '');
2668
+ if (key === lastEditorUrlPayloadKey) return;
2669
+ lastEditorUrlPayloadKey = key;
2670
+ send('editor-url-changed', payload);
2671
+ }
2672
+ function emitEditorUrlChanged(rawUrl) {
2673
+ var payload = parseEditorUrlPayload(rawUrl);
2674
+ emitEditorUrlChangedPayload(payload);
2675
+ }
2676
+
2616
2677
  function loadPage(proxyUrl) {
2617
2678
  showNoUrl(false);
2618
2679
  lastLoadedProxyUrl = proxyUrl;
@@ -2622,6 +2683,7 @@ function loadPage(proxyUrl) {
2622
2683
  iframe.style.display = 'block';
2623
2684
  setIframePageLoadingUi(true);
2624
2685
  iframe.src = appendIframeReloadBust(proxyUrl);
2686
+ emitEditorUrlChanged(proxyUrl);
2625
2687
  startIframeContentApplyWatcher(navGen, iframe.contentDocument || null);
2626
2688
  scheduleDomTreeRefresh();
2627
2689
  }
@@ -5040,6 +5102,18 @@ window.addEventListener('load', function() {
5040
5102
 
5041
5103
  // After each iframe load: apply variation, wire click+mutation handlers
5042
5104
  var iframe = document.getElementById('iframeId');
5105
+ window.addEventListener('message', function(ev) {
5106
+ try {
5107
+ var d = ev && ev.data;
5108
+ if (!d || d.channel !== 'vvveb-proxy-url' || d.type !== 'editor-url-changed') return;
5109
+ if (!iframe || !iframe.contentWindow || ev.source !== iframe.contentWindow) return;
5110
+ var payload = d.payload || {};
5111
+ emitEditorUrlChangedPayload({
5112
+ url: payload.url || undefined,
5113
+ password: payload.password || undefined,
5114
+ });
5115
+ } catch(_) {}
5116
+ });
5043
5117
  iframe.addEventListener('load', function() {
5044
5118
  if (!iframe.src || iframe.src === 'about:blank' || iframe.src === window.location.href) return;
5045
5119
  var doc = iframe.contentDocument;
@@ -5050,6 +5124,7 @@ window.addEventListener('load', function() {
5050
5124
  }
5051
5125
  var docUrl = '';
5052
5126
  try { docUrl = String(doc.URL || ''); } catch(_) {}
5127
+ emitEditorUrlChanged(iframe.src || docUrl);
5053
5128
  // Stale events: src may already be the proxy URL while the document is still
5054
5129
  // about:blank (e.g. src cleared then reset to force reload). Ask sync path to retry.
5055
5130
  if (docUrl === 'about:blank') {
@@ -5314,6 +5389,8 @@ function createVisualEditorMiddleware(options) {
5314
5389
  const targetUrl = url.searchParams.get("url");
5315
5390
  const password = url.searchParams.get("password") || "";
5316
5391
  const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
5392
+ const proxyParam = (url.searchParams.get("proxy") || "").toLowerCase();
5393
+ const useScraperProxy = proxyParam === "1" || proxyParam === "true" || proxyParam === "yes";
5317
5394
  const strictObserverFreezeForRequest = strictFreezeParam === "1" || strictFreezeParam === "true" || strictFreezeParam === "yes" ? true : strictFreezeParam === "0" || strictFreezeParam === "false" || strictFreezeParam === "no" ? false : strictObserverFreeze;
5318
5395
  if (!targetUrl) {
5319
5396
  res.statusCode = 400;
@@ -5323,13 +5400,37 @@ function createVisualEditorMiddleware(options) {
5323
5400
  const parsed = new URL(targetUrl);
5324
5401
  const origin = parsed.origin;
5325
5402
  const method = (req.method || "GET").toUpperCase();
5403
+ const scraperProxyClient = useScraperProxy ? await getScraperProxyClient() : null;
5404
+ if (useScraperProxy && !scraperProxyClient) {
5405
+ res.statusCode = 500;
5406
+ res.setHeader("Content-Type", "application/json");
5407
+ res.end(
5408
+ JSON.stringify({
5409
+ error: "ScraperAPI proxy is not configured. Set SCRAPERAPI_PROXY_PASSWORD or SCRAPERAPI_API_KEY."
5410
+ })
5411
+ );
5412
+ return;
5413
+ }
5414
+ if (!SCRAPER_PROXY_PASSWORD) ;
5415
+ const upstreamFetch = (input, init = {}) => {
5416
+ if (!useScraperProxy || !scraperProxyClient) {
5417
+ const scraperUrl = new URL(SCRAPER_API_ENDPOINT);
5418
+ scraperUrl.searchParams.set("api_key", SCRAPER_PROXY_PASSWORD);
5419
+ scraperUrl.searchParams.set("url", input);
5420
+ return fetch(scraperUrl.toString(), init);
5421
+ }
5422
+ return scraperProxyClient.fetchFn(input, {
5423
+ ...init,
5424
+ dispatcher: scraperProxyClient.dispatcher
5425
+ });
5426
+ };
5326
5427
  const headers = {
5327
5428
  "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
5328
5429
  Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
5329
5430
  };
5330
5431
  let cookieHeader = "";
5331
5432
  if (password) {
5332
- const passResp = await fetch(`${origin}/password`, {
5433
+ const passResp = await upstreamFetch(`${origin}/password`, {
5333
5434
  method: "POST",
5334
5435
  headers: {
5335
5436
  "Content-Type": "application/x-www-form-urlencoded",
@@ -5376,7 +5477,7 @@ function createVisualEditorMiddleware(options) {
5376
5477
  const timeoutId = setTimeout(() => ac.abort(), upstreamTimeoutMs);
5377
5478
  let upstream;
5378
5479
  try {
5379
- upstream = await fetch(targetUrl, {
5480
+ upstream = await upstreamFetch(targetUrl, {
5380
5481
  method,
5381
5482
  headers: fetchHeaders,
5382
5483
  body: requestBody ? Buffer.from(requestBody) : null,
@@ -5386,11 +5487,27 @@ function createVisualEditorMiddleware(options) {
5386
5487
  } catch (fetchErr) {
5387
5488
  clearTimeout(timeoutId);
5388
5489
  const aborted = fetchErr?.name === "AbortError";
5490
+ const fetchCause = fetchErr?.cause;
5389
5491
  res.statusCode = aborted ? 504 : 502;
5390
5492
  res.setHeader("Content-Type", "application/json");
5391
5493
  res.end(
5392
5494
  JSON.stringify({
5393
- error: aborted ? `Upstream request timed out after ${upstreamTimeoutMs / 1e3}s` : fetchErr?.message || "Upstream fetch failed"
5495
+ error: aborted ? `Upstream request timed out after ${upstreamTimeoutMs / 1e3}s` : fetchErr?.message || "Upstream fetch failed",
5496
+ phase: useScraperProxy ? "scraperapi-proxy-fetch" : "scraperapi-simple-fetch",
5497
+ fetchMode: useScraperProxy ? "proxy" : "simple",
5498
+ scraperapi: {
5499
+ host: SCRAPER_PROXY_HOST,
5500
+ port: SCRAPER_PROXY_PORT,
5501
+ username: SCRAPER_PROXY_USERNAME,
5502
+ endpoint: SCRAPER_API_ENDPOINT,
5503
+ hasProxyPassword: Boolean(SCRAPER_PROXY_PASSWORD),
5504
+ requestTlsRejectUnauthorized: SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED
5505
+ },
5506
+ cause: fetchCause && typeof fetchCause === "object" ? {
5507
+ name: fetchCause.name,
5508
+ code: fetchCause.code,
5509
+ message: fetchCause.message
5510
+ } : fetchCause ? String(fetchCause) : null
5394
5511
  })
5395
5512
  );
5396
5513
  return;
@@ -5421,7 +5538,7 @@ function createVisualEditorMiddleware(options) {
5421
5538
  }
5422
5539
  html = html.replace(/(href|src|action)="\/(?!\/)/g, `$1="${origin}/`);
5423
5540
  const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5424
- const proxyBase = `/api/conversion-proxy?__ve_reload=${Date.now()}&password=${encodeURIComponent(password)}&url=`;
5541
+ const proxyBase = `/api/conversion-proxy?password=${encodeURIComponent(password)}&url=`;
5425
5542
  html = html.replace(
5426
5543
  new RegExp(`(href|action)="${escapedOrigin}(/[^"]*)"`, "g"),
5427
5544
  (match, attr, urlPath) => {
@@ -5432,6 +5549,12 @@ function createVisualEditorMiddleware(options) {
5432
5549
  return `${attr}="${proxyBase}${encodeURIComponent(origin + urlPath)}"`;
5433
5550
  }
5434
5551
  );
5552
+ html = html.replace(
5553
+ /data-link="\/(?!\/)([^"]*)"/g,
5554
+ (_match, pathPart) => `data-link="/api/conversion-proxy?password=${encodeURIComponent(password)}&url=${encodeURIComponent(
5555
+ `${origin}/${pathPart}`
5556
+ )}"`
5557
+ );
5435
5558
  if (html.includes("</head>")) {
5436
5559
  html = html.replace(
5437
5560
  "</head>",
@@ -5453,10 +5576,125 @@ var TARGET_ORIGIN=${JSON.stringify(origin)};
5453
5576
  var TARGET_PAGE_URL=${JSON.stringify(targetUrl)};
5454
5577
  var PROXY_PASSWORD=${JSON.stringify(password)};
5455
5578
  var STRICT_OBSERVER_FREEZE=${JSON.stringify(strictObserverFreezeForRequest)};
5579
+ var PARENT_URL_CHANNEL="vvveb-proxy-url";
5456
5580
  window.__CONVERSION_EDITOR_ACTIVE__=true;
5581
+ window.__EDITOR_MODE__=true;
5582
+ window.CONVERSION_DISABLE_TRACKING=true;
5583
+ window.SNOWPLOW_ENABLED=false;
5584
+ 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"];
5587
+ function hasMarker(value,markers){
5588
+ var text=String(value||"").toLowerCase();
5589
+ for(var i=0;i<markers.length;i++){
5590
+ if(text.indexOf(markers[i])!==-1) return true;
5591
+ }
5592
+ return false;
5593
+ }
5594
+ function isPeriodicCollectPayload(data){
5595
+ try{
5596
+ if(data==null) return false;
5597
+ if(typeof data==="string"){
5598
+ if(data.indexOf('"r":"periodic"')!==-1||data.indexOf('"r": "periodic"')!==-1) return true;
5599
+ try{
5600
+ var parsed=JSON.parse(data);
5601
+ return !!(parsed&&parsed.r==="periodic");
5602
+ }catch(_){}
5603
+ return false;
5604
+ }
5605
+ if(typeof URLSearchParams!=="undefined"&&data instanceof URLSearchParams){
5606
+ return data.get("r")==="periodic";
5607
+ }
5608
+ if(typeof FormData!=="undefined"&&data instanceof FormData){
5609
+ return data.get("r")==="periodic";
5610
+ }
5611
+ if(typeof data==="object"){
5612
+ return !!(data&&data.r==="periodic");
5613
+ }
5614
+ }catch(_){}
5615
+ return false;
5616
+ }
5617
+ function shouldBlockEditorTracking(rawUrl){
5618
+ try{
5619
+ var u=new URL(String(rawUrl||""),window.location.href);
5620
+ var host=(u.hostname||"").toLowerCase();
5621
+ var path=(u.pathname||"").toLowerCase();
5622
+ var q=u.searchParams;
5623
+ var hasViewportPing=q.has("vp")&&(q.has("pp_miy")||q.has("pp_may"));
5624
+ var hasSessionIds=q.has("sid")||q.has("duid");
5625
+ var looksLikeHeartbeatPayload=hasViewportPing&&hasSessionIds;
5626
+ var isCrossOriginCollector=host!==TARGET_HOSTNAME&&hasMarker(host,TRACKING_HOST_MARKERS)&&hasMarker(path,TRACKING_PATH_MARKERS);
5627
+ var isSnowplowStylePath=path==="/i"||path.indexOf("/com.snowplowanalytics.snowplow/")!==-1||path.indexOf("/tp2")!==-1;
5628
+ var isTaboolaUnip=host==="trc-events.taboola.com"&&//log/d+/unip(?:/|$)/.test(path);
5629
+ var isCollectApiPath=path==="/api/collect"||path.indexOf("/api/collect/")===0;
5630
+ return isCrossOriginCollector||(looksLikeHeartbeatPayload&&isSnowplowStylePath)||isCollectApiPath||isTaboolaUnip;
5631
+ }catch(_){
5632
+ try{
5633
+ 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;
5635
+ }catch(__){
5636
+ return false;
5637
+ }
5638
+ }
5639
+ }
5640
+ try{
5641
+ if(typeof window.snowplow==="function"){
5642
+ try{window.snowplow("disableActivityTracking");}catch(_){}
5643
+ try{window.snowplow("disableAnonymousTracking");}catch(_){}
5644
+ }
5645
+ }catch(_){}
5646
+ try{
5647
+ if(!window.__CONVERSION_TRACKING_GUARD__){
5648
+ window.__CONVERSION_TRACKING_GUARD__=true;
5649
+ if(window.fetch&&typeof window.fetch==="function"){
5650
+ var _trackingFetch=window.fetch.bind(window);
5651
+ window.fetch=function(input,init){
5652
+ try{
5653
+ var raw=typeof input==="string"?input:(input&&input.url?String(input.url):"");
5654
+ var body=init&&Object.prototype.hasOwnProperty.call(init,"body")?init.body:null;
5655
+ var blockCollectPeriodic=raw&&String(raw).indexOf("/api/collect")!==-1&&isPeriodicCollectPayload(body);
5656
+ if(window.__CONVERSION_EDITOR_ACTIVE__&&(shouldBlockEditorTracking(raw)||blockCollectPeriodic)){
5657
+ return Promise.resolve(new Response("",{status:204,statusText:"No Content"}));
5658
+ }
5659
+ }catch(_){}
5660
+ return _trackingFetch(input,init);
5661
+ };
5662
+ }
5663
+ if(window.XMLHttpRequest&&window.XMLHttpRequest.prototype){
5664
+ if(typeof window.XMLHttpRequest.prototype.open==="function"){
5665
+ var _trackingOpen=window.XMLHttpRequest.prototype.open;
5666
+ window.XMLHttpRequest.prototype.open=function(method,url){
5667
+ try{
5668
+ if(window.__CONVERSION_EDITOR_ACTIVE__&&shouldBlockEditorTracking(url)){
5669
+ arguments[1]="data:text/plain,{}";
5670
+ }
5671
+ }catch(_){}
5672
+ return _trackingOpen.apply(this,arguments);
5673
+ };
5674
+ }
5675
+ }
5676
+ if(window.navigator&&typeof window.navigator.sendBeacon==="function"){
5677
+ var _trackingBeacon=window.navigator.sendBeacon.bind(window.navigator);
5678
+ window.navigator.sendBeacon=function(url,data){
5679
+ try{
5680
+ var blockCollectPeriodic=url&&String(url).indexOf("/api/collect")!==-1&&isPeriodicCollectPayload(data);
5681
+ if(window.__CONVERSION_EDITOR_ACTIVE__&&(shouldBlockEditorTracking(url)||blockCollectPeriodic)) return true;
5682
+ }catch(_){}
5683
+ return _trackingBeacon(url,data);
5684
+ };
5685
+ }
5686
+ }
5687
+ }catch(_){}
5688
+ function getEditorUrlPayload(){try{var u=new URL(window.location.href);var nested=u.searchParams.get("url");return{url:nested||u.toString(),password:u.searchParams.get("password")||undefined};}catch(_){return null;}}
5689
+ function notifyEditorUrlChanged(){try{var payload=getEditorUrlPayload();if(!payload)return;if(window.parent){window.parent.postMessage({channel:PARENT_URL_CHANNEL,type:"editor-url-changed",payload:payload},"*");}}catch(_){}}
5690
+ try{notifyEditorUrlChanged();}catch(_){}
5691
+ try{if(window.history&&typeof window.history.pushState==="function"){var nativePushState=window.history.pushState;window.history.pushState=function(){var ret=nativePushState.apply(window.history,arguments);setTimeout(notifyEditorUrlChanged,0);return ret;};}}catch(_){}
5692
+ try{if(window.history&&typeof window.history.replaceState==="function"){var nativeReplaceState=window.history.replaceState;window.history.replaceState=function(){var ret=nativeReplaceState.apply(window.history,arguments);setTimeout(notifyEditorUrlChanged,0);return ret;};}}catch(_){}
5693
+ try{window.addEventListener("popstate",notifyEditorUrlChanged,true);}catch(_){}
5694
+ try{window.addEventListener("hashchange",notifyEditorUrlChanged,true);}catch(_){}
5457
5695
  function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
5458
5696
  function toAbsolute(raw){if(isSkippable(raw))return raw;try{var base=raw.startsWith("/")||raw.startsWith("//")?TARGET_ORIGIN:TARGET_PAGE_URL;return new URL(raw,base).toString();}catch(_){return raw;}}
5459
- function toProxy(raw){if(isSkippable(raw))return null;var abs=toAbsolute(raw);if(!abs||typeof abs!=="string")return null;try{var parsed=new URL(abs);if(parsed.origin!==TARGET_ORIGIN)return null;return "/api/conversion-proxy?__ve_reload="+Date.now()+"&password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());}catch(_){return null;}}
5697
+ function toProxy(raw){if(isSkippable(raw))return null;var abs=toAbsolute(raw);if(!abs||typeof abs!=="string")return null;try{var parsed=new URL(abs);if(parsed.origin!==TARGET_ORIGIN)return null;return "/api/conversion-proxy?password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());}catch(_){return null;}}
5460
5698
  var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
5461
5699
  var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
5462
5700
  function safeNavigate(raw,mode){var abs=toAbsolute(raw);var prox=toProxy(raw);if(!prox){try{console.warn("[conversion-proxy] redirect blocked",{mode:mode,requested:raw,resolved:abs,origin:TARGET_ORIGIN});}catch(_){}return false;}try{console.info("[conversion-proxy] redirect intercepted",{mode:mode,requested:raw,resolved:abs,proxied:prox});if(mode==="replace"&&nativeReplace){nativeReplace(prox);return true;}if(nativeAssign){nativeAssign(prox);return true;}window.location.href=prox;return true;}catch(err){try{console.warn("[conversion-proxy] redirect interception failed",{mode:mode,requested:raw,resolved:abs,proxied:prox,error:err&&err.message?err.message:String(err)});}catch(_){}return false;}}
@@ -5537,9 +5775,9 @@ if(window.fetch){
5537
5775
  }
5538
5776
  if(window.XMLHttpRequest&&window.XMLHttpRequest.prototype&&window.XMLHttpRequest.prototype.open){var _open=window.XMLHttpRequest.prototype.open;window.XMLHttpRequest.prototype.open=function(method,url){try{var u=resolveUrl(String(url));if(u&&isNestedMalformedProxy(u)){arguments[1]=EMPTY_JSON_DATA;}else{arguments[1]=toAbsoluteOriginUrl(url);}}catch(_){}return _open.apply(this,arguments);};}
5539
5777
  if(window.navigator&&typeof window.navigator.sendBeacon==="function"){var _beacon=window.navigator.sendBeacon.bind(window.navigator);window.navigator.sendBeacon=function(url,data){try{if(skipNestedProxyNetwork(String(url)))return true;}catch(_){}return _beacon(url,data);};}
5540
- function withReloadBust(urlRaw){try{var u=resolveUrl(String(urlRaw||""));if(!u)return null;var p=u.pathname||"";var isRootProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0;if(!isRootProxyPath)return null;u.searchParams.set("__ve_reload",String(Date.now()));return u.toString();}catch(_){return null;}}
5541
- document.addEventListener("click",function(ev){try{var t=ev&&ev.target;if(!t||!t.closest)return;var a=t.closest("a[href]");if(!a)return;var href=a.getAttribute("href")||a.href;var bust=withReloadBust(href);if(bust)a.setAttribute("href",bust);}catch(_){}},true);
5542
- document.addEventListener("submit",function(ev){try{var f=ev&&ev.target;if(!f||!f.getAttribute)return;var act=f.getAttribute("action")||"";var bust=withReloadBust(act);if(bust)f.setAttribute("action",bust);}catch(_){}},true);
5778
+ function withReloadBust(urlRaw){try{var u=resolveUrl(String(urlRaw||""));if(!u)return null;var p=u.pathname||"";var isRootProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0;if(!isRootProxyPath)return null;return u.toString();}catch(_){return null;}}
5779
+ document.addEventListener("click",function(ev){try{var t=ev&&ev.target;if(!t||!t.closest)return;var a=t.closest("a[href]");if(a){var href=a.getAttribute("href")||a.href||"";var hasModifier=!!(ev.metaKey||ev.ctrlKey||ev.shiftKey||ev.altKey);var targetAttr=(a.getAttribute("target")||"").toLowerCase();var isNewTab=targetAttr==="_blank";var isDownload=!!a.getAttribute("download");if(hasModifier||isNewTab||isDownload)return;var prox=toProxy(href);if(!prox)return;a.setAttribute("href",prox);if(ev&&typeof ev.preventDefault==="function")ev.preventDefault();safeNavigate(href,"assign");return;}var summary=t.closest("summary[data-link]");if(summary&&summary.getAttribute){var raw=summary.getAttribute("data-link")||"";if(raw){var prox2=toProxy(raw);if(prox2){summary.setAttribute("data-link",prox2);if(ev&&typeof ev.preventDefault==="function")ev.preventDefault();safeNavigate(raw,"assign");}}}}catch(_){}},true);
5780
+ document.addEventListener("submit",function(ev){try{var f=ev&&ev.target;if(!f||!f.getAttribute)return;var act=f.getAttribute("action")||window.location.href;var prox=toProxy(act);if(prox)f.setAttribute("action",prox);}catch(_){}},true);
5543
5781
  if(window.navigator&&window.navigator.serviceWorker&&typeof window.navigator.serviceWorker.register==="function"){window.navigator.serviceWorker.register=function(){return Promise.resolve({scope:"disabled-in-editor-proxy"});};}
5544
5782
  }catch(_){}})();</script>`;
5545
5783
  if (html.includes("</head>")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@accelerated-agency/visual-editor",
3
- "version": "0.3.5",
3
+ "version": "0.3.8",
4
4
  "private": false,
5
5
  "description": "Conversion visual editor as a reusable React package",
6
6
  "type": "module",
@@ -36,6 +36,7 @@
36
36
  "bootstrap-icons": "^1.13.1",
37
37
  "lucide-react": "^0.562.0",
38
38
  "react-colorful": "^5.6.1",
39
+ "undici": "^6.21.3",
39
40
  "zustand": "^5.0.7"
40
41
  },
41
42
  "devDependencies": {