@accelerated-agency/visual-editor 0.4.5 → 0.4.7

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.
Files changed (3) hide show
  1. package/dist/vite.cjs +255 -106
  2. package/dist/vite.js +255 -106
  3. package/package.json +1 -1
package/dist/vite.cjs CHANGED
@@ -11,20 +11,6 @@ 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;
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
14
  var DEFAULT_TRACKING_MARKERS = [
29
15
  "snowplow",
30
16
  "taboola",
@@ -122,31 +108,9 @@ function stripTrackingScriptsFromScrapedHtml(html, markers) {
122
108
  }
123
109
  return out;
124
110
  }
125
- var SCRAPER_BILLING_ERROR_RE = /exhausted the api credits|upgrade your subscription|enable overages|dashboard\.scraperapi\.com\/billing|insufficient credits|billing/i;
126
- var scraperProxyClientPromise = null;
127
- async function getScraperProxyClient() {
128
- if (scraperProxyClientPromise) return scraperProxyClientPromise;
129
- scraperProxyClientPromise = (async () => {
130
- if (!SCRAPER_PROXY_PASSWORD) return null;
131
- try {
132
- const undici = await import('undici');
133
- const proxyUrl = "http://" + encodeURIComponent(SCRAPER_PROXY_USERNAME) + ":" + encodeURIComponent(SCRAPER_PROXY_PASSWORD) + "@" + SCRAPER_PROXY_HOST + ":" + String(SCRAPER_PROXY_PORT);
134
- return {
135
- dispatcher: new undici.ProxyAgent({
136
- uri: proxyUrl,
137
- requestTls: {
138
- rejectUnauthorized: SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED
139
- }
140
- }),
141
- fetchFn: undici.fetch
142
- };
143
- } catch (_) {
144
- return null;
145
- }
146
- })();
147
- return scraperProxyClientPromise;
148
- }
149
- 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>`;
111
+ var iframeAlwaysShowCss = `<style id="__ce_force_show">
112
+
113
+ </style>`;
150
114
  var iframeAlwaysShowCssGuardScript = `<script id="__ce_force_show_guard">(function(){try{
151
115
  function ensureForceShowStyleLast(){
152
116
  var style=document.getElementById("__ce_force_show");
@@ -505,7 +469,10 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
505
469
  .dt-ico{width:16px;flex-shrink:0;text-align:center;color:var(--text-3);font-size:12px}
506
470
  .dt-lbl{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,monospace;font-size:10px}
507
471
  .dt-muted{padding:16px 12px;text-align:center;color:var(--text-3);font-size:11px;line-height:1.4}
508
-
472
+ #section-components-panel{
473
+ max-height: 50%;
474
+ overflow-y: auto;
475
+ }
509
476
  /* \u2500\u2500 Right panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
510
477
  #right-panel{
511
478
  width:252px;background:var(--bg);border-left:1px solid var(--border);
@@ -634,6 +601,17 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
634
601
  flex:1;padding:8px 2px;text-align:center;font-size:10px;color:var(--text-3);
635
602
  cursor:pointer;border-bottom:2px solid transparent;transition:all .15s;font-weight:600;line-height:1.15
636
603
  }
604
+ .lp-tab.close-section-components-panel{
605
+ padding: 4px 10px;
606
+ background: #000;
607
+ display: flex;
608
+ max-width: fit-content;
609
+ align-items: center;
610
+ justify-content: center;
611
+ border-radius: 2px;
612
+ margin: 2px;
613
+ color: #fff;
614
+ }
637
615
  .lp-tab:hover{color:var(--text-2)}
638
616
  .lp-tab.active{color:var(--accent-txt);border-bottom-color:var(--accent)}
639
617
  .future-hidden{display:none!important}
@@ -1142,6 +1120,7 @@ select.pr-inp{cursor:pointer;background:#fff}
1142
1120
  <div class="section-components-tabs">
1143
1121
  <div class="lp-tab" onclick="switchSectionComponentsTab('components')">Components</div>
1144
1122
  <div class="lp-tab" onclick="switchSectionComponentsTab('sections')">Sections</div>
1123
+ <div class="lp-tab close-section-components-panel" onclick="toggleSectionComponentsPanel()"> Close</div>
1145
1124
  </div>
1146
1125
  <div class="lp-body">
1147
1126
  <div id="tab-components" class="tab-pane"></div>
@@ -3266,6 +3245,35 @@ function parseEditorUrlPayload(rawUrl) {
3266
3245
  password: nestedPassword || undefined,
3267
3246
  };
3268
3247
  }
3248
+ var path = parsed.pathname || '';
3249
+ var isProxyPath =
3250
+ path === '/api/conversion-proxy' ||
3251
+ path.indexOf('/api/conversion-proxy/') === 0 ||
3252
+ path.indexOf('api/conversion-proxy') !== -1;
3253
+ if (isProxyPath) {
3254
+ var fallbackUrl = (experimentData && experimentData.pageUrl) ? String(experimentData.pageUrl) : '';
3255
+ if (fallbackUrl) {
3256
+ var recovered = new URL(fallbackUrl, window.location.href);
3257
+ var qp = new URLSearchParams(parsed.search || '');
3258
+ qp.delete('url');
3259
+ qp.delete('password');
3260
+ qp.delete('conversionProxyBaseUrl');
3261
+ qp.delete('trackingMarkers');
3262
+ qp.delete('strictObserverFreeze');
3263
+ qp.delete('proxy');
3264
+ qp.delete('raw');
3265
+ recovered.search = '';
3266
+ qp.forEach(function(v, k) { recovered.searchParams.set(k, v); });
3267
+ recovered.hash = parsed.hash || '';
3268
+ return {
3269
+ url: recovered.toString(),
3270
+ password:
3271
+ (experimentData && experimentData.editorPassword)
3272
+ ? String(experimentData.editorPassword)
3273
+ : undefined,
3274
+ };
3275
+ }
3276
+ }
3269
3277
  return {
3270
3278
  url: parsed.toString(),
3271
3279
  password:
@@ -3284,6 +3292,12 @@ function emitEditorUrlChangedPayload(payload) {
3284
3292
  var key = String(payload.url || '') + '|' + String(payload.password || '');
3285
3293
  if (key === lastEditorUrlPayloadKey) return;
3286
3294
  lastEditorUrlPayloadKey = key;
3295
+ try {
3296
+ console.info('[V2 iframe-url]', {
3297
+ url: payload.url || '',
3298
+ passwordPresent: !!payload.password,
3299
+ });
3300
+ } catch(_) {}
3287
3301
  send('editor-url-changed', payload);
3288
3302
  }
3289
3303
  function emitEditorUrlChanged(rawUrl) {
@@ -5056,6 +5070,67 @@ function stripDataVveInstanceSubtree(root) {
5056
5070
  }
5057
5071
  }
5058
5072
 
5073
+ function cssEscapeIdent(raw) {
5074
+ var s = raw == null ? '' : String(raw);
5075
+ if (!s) return '';
5076
+ try {
5077
+ if (typeof CSS !== 'undefined' && CSS && typeof CSS.escape === 'function') {
5078
+ return CSS.escape(s);
5079
+ }
5080
+ } catch(_) {}
5081
+ // Fallback escape for identifiers when CSS.escape is unavailable.
5082
+ return s.replace(/[^a-zA-Z0-9_-]/g, function(ch) { return '\\\\' + ch; });
5083
+ }
5084
+
5085
+ function unescapeCssToken(token) {
5086
+ if (!token) return '';
5087
+ var s = String(token);
5088
+ var out = '';
5089
+ for (var i = 0; i < s.length; i++) {
5090
+ var ch = s.charAt(i);
5091
+ if (ch === '\\\\' && i + 1 < s.length) {
5092
+ out += s.charAt(i + 1);
5093
+ i += 1;
5094
+ continue;
5095
+ }
5096
+ out += ch;
5097
+ }
5098
+ return out;
5099
+ }
5100
+
5101
+ function isGeneratedClassToken(token) {
5102
+ var t = token == null ? '' : String(token).trim();
5103
+ if (!t) return true;
5104
+ if (t.indexOf('vve-') === 0) return true;
5105
+ // Tailwind arbitrary values / variant-heavy utilities are often unstable in selectors.
5106
+ if (
5107
+ t.indexOf('[') !== -1 ||
5108
+ t.indexOf(']') !== -1 ||
5109
+ t.indexOf('(') !== -1 ||
5110
+ t.indexOf(')') !== -1 ||
5111
+ t.indexOf('{') !== -1 ||
5112
+ t.indexOf('}') !== -1 ||
5113
+ t.indexOf(':') !== -1
5114
+ ) return true;
5115
+ // CSS-in-JS / runtime hash prefixes.
5116
+ if (/^(css|jsx|sc|emotion|styled|chakra|mantine|mui|ant)-/i.test(t)) return true;
5117
+ // Classnames with long hashy suffixes (framework/runtime generated).
5118
+ if (/[a-f0-9]{8,}/i.test(t)) return true;
5119
+ if (/^[a-zA-Z_-]+[0-9]{4,}[a-zA-Z0-9_-]*$/.test(t)) return true;
5120
+ if (/^[a-zA-Z0-9_-]{36,}$/.test(t)) return true;
5121
+ return false;
5122
+ }
5123
+
5124
+ function escapeSelectorClassTokens(sel) {
5125
+ if (!sel || typeof sel !== 'string') return '';
5126
+ return sel.replace(/.((?:\\.|[^s>+~:#.])+)/g, function(_m, cls) {
5127
+ if (!cls) return _m;
5128
+ // Already escaped token; keep it as-is.
5129
+ if (cls.indexOf('\\\\') >= 0) return '.' + cls;
5130
+ return '.' + cssEscapeIdent(cls);
5131
+ });
5132
+ }
5133
+
5059
5134
  function buildSelector(el) {
5060
5135
  if (!el) return '';
5061
5136
  var doc = el.ownerDocument || document;
@@ -5067,16 +5142,16 @@ function buildSelector(el) {
5067
5142
  if (doc.querySelectorAll(attrSel).length === 1) return attrSel;
5068
5143
  } catch(_) {}
5069
5144
  }
5070
- if (el.id) return '#' + el.id;
5145
+ if (el.id) return '#' + cssEscapeIdent(el.id);
5071
5146
  var parts = [], node = el, depth = 0;
5072
5147
  while (node && node.nodeType === 1 && depth < 5) {
5073
- if (node.id) { parts.unshift('#' + node.id); break; }
5148
+ if (node.id) { parts.unshift('#' + cssEscapeIdent(node.id)); break; }
5074
5149
  var p = node.tagName.toLowerCase();
5075
5150
  if (node.classList && node.classList.length) {
5076
5151
  var clsArr = Array.from(node.classList).filter(function(c) {
5077
- return c.indexOf('vve-') !== 0;
5152
+ return c.indexOf('vve-') !== 0 && !isGeneratedClassToken(c);
5078
5153
  });
5079
- if (clsArr.length) p += '.' + clsArr.slice(0, 2).join('.');
5154
+ if (clsArr.length) p += '.' + clsArr.slice(0, 2).map(function(c) { return cssEscapeIdent(c); }).join('.');
5080
5155
  }
5081
5156
  var idx = 1, sib = node.previousElementSibling;
5082
5157
  while (sib) { if (sib.tagName === node.tagName) idx++; sib = sib.previousElementSibling; }
@@ -5088,17 +5163,32 @@ function buildSelector(el) {
5088
5163
  return parts.join(' > ');
5089
5164
  }
5090
5165
 
5166
+ function stripGeneratedSelectorClassTokens(sel) {
5167
+ if (!sel || typeof sel !== 'string') return '';
5168
+ var s = sel.replace(/.((?:\\.|[^s>+~:#.])+)/g, function(_m, cls) {
5169
+ var raw = unescapeCssToken(cls);
5170
+ if (isGeneratedClassToken(raw)) return '';
5171
+ return '.' + cssEscapeIdent(raw);
5172
+ });
5173
+ return s
5174
+ .replace(/.{2,}/g, '.')
5175
+ .replace(/s{2,}/g, ' ')
5176
+ .replace(/s*>s*>/g, ' > ')
5177
+ .trim();
5178
+ }
5179
+
5091
5180
  /**
5092
5181
  * Strip editor-only .vve-* class tokens from a selector string (fixes DB rows saved while an element was selected).
5093
5182
  */
5094
5183
  function sanitizeSelectorForMatch(sel) {
5095
5184
  if (!sel || typeof sel !== 'string') return '';
5096
5185
  var s0 = sel.replace(/.vve-[a-zA-Z0-9_-]+/gi, '');
5186
+ s0 = stripGeneratedSelectorClassTokens(s0);
5097
5187
  var parts = s0.split(/s*>s*/).map(function(seg) {
5098
5188
  var t = seg.replace(/.+/g, '.').replace(/.$/, '');
5099
5189
  return t.trim();
5100
5190
  });
5101
- return parts.filter(Boolean).join(' > ');
5191
+ return escapeSelectorClassTokens(parts.filter(Boolean).join(' > '));
5102
5192
  }
5103
5193
 
5104
5194
  /** Drop the rightmost :nth-of-type(n) (hydration / layout often shifts sibling indices). */
@@ -5142,11 +5232,12 @@ function querySelectorResolved(iframeDoc, selector) {
5142
5232
  return null;
5143
5233
  }
5144
5234
  var alt = sanitizeSelectorForMatch(selector);
5235
+ var escaped = escapeSelectorClassTokens(alt || selector);
5145
5236
  // Prefer sanitized + nth relax FIRST: raw selectors often still contain .vve-* from
5146
5237
  // save-time selection; those only match after clicking (we re-add vve-selected).
5147
- var el = walkRelax(alt || selector);
5238
+ var el = walkRelax(escaped || alt || selector);
5148
5239
  if (el) return el;
5149
- if (alt !== selector) {
5240
+ if (alt !== selector || escaped !== selector) {
5150
5241
  el = walkRelax(selector);
5151
5242
  if (el) return el;
5152
5243
  }
@@ -5813,6 +5904,12 @@ window.addEventListener('load', function() {
5813
5904
  if (!d || d.channel !== 'vvveb-proxy-url' || d.type !== 'editor-url-changed') return;
5814
5905
  if (!iframe || !iframe.contentWindow || ev.source !== iframe.contentWindow) return;
5815
5906
  var payload = d.payload || {};
5907
+ try {
5908
+ console.info('[V2 iframe-url bridge]', {
5909
+ url: payload.url || '',
5910
+ passwordPresent: !!payload.password,
5911
+ });
5912
+ } catch(_) {}
5816
5913
  emitEditorUrlChangedPayload({
5817
5914
  url: payload.url || undefined,
5818
5915
  password: payload.password || undefined,
@@ -6102,8 +6199,6 @@ function createVisualEditorMiddleware(options) {
6102
6199
  extraTrackingMarkersForRequest
6103
6200
  );
6104
6201
  const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
6105
- const proxyParam = (url.searchParams.get("proxy") || "").toLowerCase();
6106
- const useScraperProxy = proxyParam === "1" || proxyParam === "true" || proxyParam === "yes";
6107
6202
  const strictObserverFreezeForRequest = strictFreezeParam === "1" || strictFreezeParam === "true" || strictFreezeParam === "yes" ? true : strictFreezeParam === "0" || strictFreezeParam === "false" || strictFreezeParam === "no" ? false : strictObserverFreeze;
6108
6203
  if (!targetUrl) {
6109
6204
  res.statusCode = 400;
@@ -6113,40 +6208,7 @@ function createVisualEditorMiddleware(options) {
6113
6208
  const parsed = new URL(targetUrl);
6114
6209
  const origin = parsed.origin;
6115
6210
  const method = (req.method || "GET").toUpperCase();
6116
- const scraperProxyClient = useScraperProxy ? await getScraperProxyClient() : null;
6117
- if (useScraperProxy && !scraperProxyClient) {
6118
- res.statusCode = 500;
6119
- res.setHeader("Content-Type", "application/json");
6120
- res.end(
6121
- JSON.stringify({
6122
- error: "ScraperAPI proxy is not configured. Set SCRAPERAPI_PROXY_PASSWORD or SCRAPERAPI_API_KEY."
6123
- })
6124
- );
6125
- return;
6126
- }
6127
6211
  const directFetch = (input, init = {}) => fetch(input, init);
6128
- const scraperFetch = (input, init = {}) => {
6129
- if (!SCRAPER_PROXY_PASSWORD) return directFetch(input, init);
6130
- if (!useScraperProxy || !scraperProxyClient) {
6131
- const scraperUrl = new URL(SCRAPER_API_ENDPOINT);
6132
- scraperUrl.searchParams.set("api_key", SCRAPER_PROXY_PASSWORD);
6133
- scraperUrl.searchParams.set("url", input);
6134
- return fetch(scraperUrl.toString(), init);
6135
- }
6136
- return scraperProxyClient.fetchFn(input, {
6137
- ...init,
6138
- dispatcher: scraperProxyClient.dispatcher
6139
- });
6140
- };
6141
- const shouldFallbackFromScraper = async (resp) => {
6142
- try {
6143
- if (resp.ok) return false;
6144
- const text = await resp.clone().text();
6145
- return SCRAPER_BILLING_ERROR_RE.test(String(text || ""));
6146
- } catch (_) {
6147
- return false;
6148
- }
6149
- };
6150
6212
  const workerRawFetch = (input, init = {}) => {
6151
6213
  const workerUrl = new URL("/api/conversion-proxy", conversionProxyBaseUrlForRequest);
6152
6214
  workerUrl.searchParams.set("url", input);
@@ -6173,19 +6235,12 @@ function createVisualEditorMiddleware(options) {
6173
6235
  };
6174
6236
  const upstreamFetch = async (input, init = {}) => {
6175
6237
  if (conversionProxyBaseUrlForRequest) {
6238
+ const method2 = String(init?.method || "GET").toUpperCase();
6239
+ if (method2 !== "GET" && method2 !== "HEAD") {
6240
+ return directFetch(input, init);
6241
+ }
6176
6242
  return workerRawFetch(input, init);
6177
6243
  }
6178
- const primary = await scraperFetch(input, init);
6179
- if (!await shouldFallbackFromScraper(primary)) {
6180
- return primary;
6181
- }
6182
- try {
6183
- console.warn("[conversion-proxy] ScraperAPI billing/quota detected; falling back to direct fetch", {
6184
- url: input,
6185
- mode: useScraperProxy ? "proxy" : "simple"
6186
- });
6187
- } catch (_) {
6188
- }
6189
6244
  return directFetch(input, init);
6190
6245
  };
6191
6246
  const headers = {
@@ -6257,16 +6312,8 @@ function createVisualEditorMiddleware(options) {
6257
6312
  res.end(
6258
6313
  JSON.stringify({
6259
6314
  error: aborted ? `Upstream request timed out after ${upstreamTimeoutMs / 1e3}s` : fetchErr?.message || "Upstream fetch failed",
6260
- phase: useScraperProxy ? "scraperapi-proxy-fetch" : "scraperapi-simple-fetch",
6261
- fetchMode: useScraperProxy ? "proxy" : "simple",
6262
- scraperapi: {
6263
- host: SCRAPER_PROXY_HOST,
6264
- port: SCRAPER_PROXY_PORT,
6265
- username: SCRAPER_PROXY_USERNAME,
6266
- endpoint: SCRAPER_API_ENDPOINT,
6267
- hasProxyPassword: Boolean(SCRAPER_PROXY_PASSWORD),
6268
- requestTlsRejectUnauthorized: SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED
6269
- },
6315
+ phase: conversionProxyBaseUrlForRequest ? "worker-raw-fetch" : "direct-upstream-fetch",
6316
+ fetchMode: conversionProxyBaseUrlForRequest ? "worker" : "direct",
6270
6317
  cause: fetchCause && typeof fetchCause === "object" ? {
6271
6318
  name: fetchCause.name,
6272
6319
  code: fetchCause.code,
@@ -6452,8 +6499,51 @@ try{
6452
6499
  }
6453
6500
  }
6454
6501
  }catch(_){}
6455
- 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;}}
6456
- 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(_){}}
6502
+ function getEditorUrlPayload(){
6503
+ try{
6504
+ var u=new URL(window.location.href);
6505
+ var nested=u.searchParams.get("url");
6506
+ if(nested){
6507
+ return {url:nested,password:u.searchParams.get("password")||undefined};
6508
+ }
6509
+ var p=u.pathname||"";
6510
+ var isProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0||p.indexOf("api/conversion-proxy")!==-1;
6511
+ if(isProxyPath){
6512
+ var recoveredBase=new URL(TARGET_PAGE_URL,window.location.href);
6513
+ var qp=new URLSearchParams(u.search||"");
6514
+ qp.delete("url");
6515
+ qp.delete("password");
6516
+ qp.delete("conversionProxyBaseUrl");
6517
+ qp.delete("trackingMarkers");
6518
+ qp.delete("strictObserverFreeze");
6519
+ qp.delete("proxy");
6520
+ qp.delete("raw");
6521
+ recoveredBase.search="";
6522
+ qp.forEach(function(v,k){recoveredBase.searchParams.set(k,v);});
6523
+ recoveredBase.hash=u.hash||"";
6524
+ return {url:recoveredBase.toString(),password:u.searchParams.get("password")||undefined};
6525
+ }
6526
+ return {url:u.toString(),password:u.searchParams.get("password")||undefined};
6527
+ }catch(_){
6528
+ return null;
6529
+ }
6530
+ }
6531
+ function notifyEditorUrlChanged(){
6532
+ try{
6533
+ var payload=getEditorUrlPayload();
6534
+ if(!payload) return;
6535
+ try{
6536
+ console.info("[conversion-proxy] iframe url rendered",{
6537
+ current:window.location.href,
6538
+ target:payload.url||"",
6539
+ passwordPresent:!!payload.password
6540
+ });
6541
+ }catch(_){}
6542
+ if(window.parent){
6543
+ window.parent.postMessage({channel:PARENT_URL_CHANNEL,type:"editor-url-changed",payload:payload},"*");
6544
+ }
6545
+ }catch(_){}
6546
+ }
6457
6547
  try{notifyEditorUrlChanged();}catch(_){}
6458
6548
  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(_){}
6459
6549
  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(_){}
@@ -6461,7 +6551,29 @@ try{window.addEventListener("popstate",notifyEditorUrlChanged,true);}catch(_){}
6461
6551
  try{window.addEventListener("hashchange",notifyEditorUrlChanged,true);}catch(_){}
6462
6552
  function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
6463
6553
  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;}}
6464
- 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;var root="/api/conversion-proxy";return root+"?password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());}catch(_){return null;}}
6554
+ function toProxy(raw){
6555
+ if(isSkippable(raw))return null;
6556
+ var abs=toAbsolute(raw);
6557
+ if(!abs||typeof abs!=="string")return null;
6558
+ try{
6559
+ var parsed=new URL(abs);
6560
+ // If input is already a proxy URL, unwrap to its target url first
6561
+ // to avoid nested /api/conversion-proxy?url=/api/conversion-proxy?... chains.
6562
+ var p=(parsed.pathname||"");
6563
+ var isProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0||p.indexOf("api/conversion-proxy")!==-1;
6564
+ if(isProxyPath){
6565
+ var nested=parsed.searchParams.get("url")||"";
6566
+ if(nested){
6567
+ try{parsed=new URL(nested);}catch(_){}
6568
+ }
6569
+ }
6570
+ if(parsed.origin!==TARGET_ORIGIN)return null;
6571
+ var root="/api/conversion-proxy";
6572
+ return root+"?password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());
6573
+ }catch(_){
6574
+ return null;
6575
+ }
6576
+ }
6465
6577
  var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
6466
6578
  var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
6467
6579
  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;}}
@@ -6511,12 +6623,49 @@ var PROXY_BASE_URL=_proxyCtx?_proxyCtx.searchParams.get("conversionProxyBaseUrl"
6511
6623
  var PROXY_TRACKING_MARKERS=_proxyCtx?_proxyCtx.searchParams.get("trackingMarkers")||"":"";
6512
6624
  var PROXY_STRICT_FREEZE=_proxyCtx?_proxyCtx.searchParams.get("strictObserverFreeze")||"":"";
6513
6625
  var PROXY_UPSTREAM_MODE=_proxyCtx?_proxyCtx.searchParams.get("proxy")||"":"";
6626
+ var EDITOR_ORIGIN=(function(){try{return String(window.location.origin||"");}catch(_){return "";}})();
6627
+ var EDITOR_HOST_KEY=(function(){try{var u=new URL(EDITOR_ORIGIN);return (u.hostname||"").toLowerCase()+":"+(u.port||"");}catch(_){return "";}})();
6514
6628
  function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
6629
+ function isEditorHostUrl(u){
6630
+ try{
6631
+ if(!u) return false;
6632
+ var hostKey=(u.hostname||"").toLowerCase()+":"+(u.port||"");
6633
+ if(EDITOR_HOST_KEY&&hostKey===EDITOR_HOST_KEY) return true;
6634
+ // localhost aliases for same dev server port
6635
+ var host=(u.hostname||"").toLowerCase();
6636
+ var editorHost=EDITOR_HOST_KEY.split(":")[0]||"";
6637
+ var samePort=(u.port||"")===(EDITOR_HOST_KEY.split(":")[1]||"");
6638
+ var localAlias=(host==="localhost"||host==="127.0.0.1"||host==="[::1]");
6639
+ var editorLocalAlias=(editorHost==="localhost"||editorHost==="127.0.0.1"||editorHost==="[::1]");
6640
+ return samePort&&localAlias&&editorLocalAlias;
6641
+ }catch(_){
6642
+ return false;
6643
+ }
6644
+ }
6515
6645
  function toProxyNetworkUrl(raw){
6516
6646
  if(isSkippable(raw))return raw;
6517
6647
  try{
6518
6648
  var base=raw.startsWith("/")?TARGET_ORIGIN:TARGET_PAGE_URL;
6519
6649
  var abs=new URL(raw,base);
6650
+ // Unwrap already-proxied URLs first to avoid nested proxy urls.
6651
+ var p0=abs.pathname||"";
6652
+ var isProxyPath0=p0==="/api/conversion-proxy"||p0.indexOf("/api/conversion-proxy/")===0||p0.indexOf("api/conversion-proxy")!==-1;
6653
+ if(isProxyPath0){
6654
+ var nested0=abs.searchParams.get("url")||"";
6655
+ if(nested0){
6656
+ try{abs=new URL(nested0);}catch(_){}
6657
+ }
6658
+ }
6659
+ // Some embedded scripts build absolute requests against editor origin
6660
+ // (e.g. https://localhost:4001/api/unstable/graphql.json). Remap those
6661
+ // paths to target origin first, then proxy as usual.
6662
+ if(EDITOR_ORIGIN&&isEditorHostUrl(abs)){
6663
+ var p=abs.pathname||"";
6664
+ var isRootProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0;
6665
+ if(!isRootProxyPath){
6666
+ abs=new URL((abs.pathname||"/")+(abs.search||"")+(abs.hash||""),TARGET_ORIGIN);
6667
+ }
6668
+ }
6520
6669
  if(abs.origin!==TARGET_ORIGIN)return raw;
6521
6670
  var prox=new URL(PROXY_ROOT,window.location.origin);
6522
6671
  prox.searchParams.set("password",PROXY_PASSWORD||"");
package/dist/vite.js CHANGED
@@ -3,20 +3,6 @@ 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;
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
6
  var DEFAULT_TRACKING_MARKERS = [
21
7
  "snowplow",
22
8
  "taboola",
@@ -114,31 +100,9 @@ function stripTrackingScriptsFromScrapedHtml(html, markers) {
114
100
  }
115
101
  return out;
116
102
  }
117
- var SCRAPER_BILLING_ERROR_RE = /exhausted the api credits|upgrade your subscription|enable overages|dashboard\.scraperapi\.com\/billing|insufficient credits|billing/i;
118
- var scraperProxyClientPromise = null;
119
- async function getScraperProxyClient() {
120
- if (scraperProxyClientPromise) return scraperProxyClientPromise;
121
- scraperProxyClientPromise = (async () => {
122
- if (!SCRAPER_PROXY_PASSWORD) return null;
123
- try {
124
- const undici = await import('undici');
125
- const proxyUrl = "http://" + encodeURIComponent(SCRAPER_PROXY_USERNAME) + ":" + encodeURIComponent(SCRAPER_PROXY_PASSWORD) + "@" + SCRAPER_PROXY_HOST + ":" + String(SCRAPER_PROXY_PORT);
126
- return {
127
- dispatcher: new undici.ProxyAgent({
128
- uri: proxyUrl,
129
- requestTls: {
130
- rejectUnauthorized: SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED
131
- }
132
- }),
133
- fetchFn: undici.fetch
134
- };
135
- } catch (_) {
136
- return null;
137
- }
138
- })();
139
- return scraperProxyClientPromise;
140
- }
141
- 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>`;
103
+ var iframeAlwaysShowCss = `<style id="__ce_force_show">
104
+
105
+ </style>`;
142
106
  var iframeAlwaysShowCssGuardScript = `<script id="__ce_force_show_guard">(function(){try{
143
107
  function ensureForceShowStyleLast(){
144
108
  var style=document.getElementById("__ce_force_show");
@@ -497,7 +461,10 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
497
461
  .dt-ico{width:16px;flex-shrink:0;text-align:center;color:var(--text-3);font-size:12px}
498
462
  .dt-lbl{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:ui-monospace,SFMono-Regular,monospace;font-size:10px}
499
463
  .dt-muted{padding:16px 12px;text-align:center;color:var(--text-3);font-size:11px;line-height:1.4}
500
-
464
+ #section-components-panel{
465
+ max-height: 50%;
466
+ overflow-y: auto;
467
+ }
501
468
  /* \u2500\u2500 Right panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
502
469
  #right-panel{
503
470
  width:252px;background:var(--bg);border-left:1px solid var(--border);
@@ -626,6 +593,17 @@ box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.20), 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 1p
626
593
  flex:1;padding:8px 2px;text-align:center;font-size:10px;color:var(--text-3);
627
594
  cursor:pointer;border-bottom:2px solid transparent;transition:all .15s;font-weight:600;line-height:1.15
628
595
  }
596
+ .lp-tab.close-section-components-panel{
597
+ padding: 4px 10px;
598
+ background: #000;
599
+ display: flex;
600
+ max-width: fit-content;
601
+ align-items: center;
602
+ justify-content: center;
603
+ border-radius: 2px;
604
+ margin: 2px;
605
+ color: #fff;
606
+ }
629
607
  .lp-tab:hover{color:var(--text-2)}
630
608
  .lp-tab.active{color:var(--accent-txt);border-bottom-color:var(--accent)}
631
609
  .future-hidden{display:none!important}
@@ -1134,6 +1112,7 @@ select.pr-inp{cursor:pointer;background:#fff}
1134
1112
  <div class="section-components-tabs">
1135
1113
  <div class="lp-tab" onclick="switchSectionComponentsTab('components')">Components</div>
1136
1114
  <div class="lp-tab" onclick="switchSectionComponentsTab('sections')">Sections</div>
1115
+ <div class="lp-tab close-section-components-panel" onclick="toggleSectionComponentsPanel()"> Close</div>
1137
1116
  </div>
1138
1117
  <div class="lp-body">
1139
1118
  <div id="tab-components" class="tab-pane"></div>
@@ -3258,6 +3237,35 @@ function parseEditorUrlPayload(rawUrl) {
3258
3237
  password: nestedPassword || undefined,
3259
3238
  };
3260
3239
  }
3240
+ var path = parsed.pathname || '';
3241
+ var isProxyPath =
3242
+ path === '/api/conversion-proxy' ||
3243
+ path.indexOf('/api/conversion-proxy/') === 0 ||
3244
+ path.indexOf('api/conversion-proxy') !== -1;
3245
+ if (isProxyPath) {
3246
+ var fallbackUrl = (experimentData && experimentData.pageUrl) ? String(experimentData.pageUrl) : '';
3247
+ if (fallbackUrl) {
3248
+ var recovered = new URL(fallbackUrl, window.location.href);
3249
+ var qp = new URLSearchParams(parsed.search || '');
3250
+ qp.delete('url');
3251
+ qp.delete('password');
3252
+ qp.delete('conversionProxyBaseUrl');
3253
+ qp.delete('trackingMarkers');
3254
+ qp.delete('strictObserverFreeze');
3255
+ qp.delete('proxy');
3256
+ qp.delete('raw');
3257
+ recovered.search = '';
3258
+ qp.forEach(function(v, k) { recovered.searchParams.set(k, v); });
3259
+ recovered.hash = parsed.hash || '';
3260
+ return {
3261
+ url: recovered.toString(),
3262
+ password:
3263
+ (experimentData && experimentData.editorPassword)
3264
+ ? String(experimentData.editorPassword)
3265
+ : undefined,
3266
+ };
3267
+ }
3268
+ }
3261
3269
  return {
3262
3270
  url: parsed.toString(),
3263
3271
  password:
@@ -3276,6 +3284,12 @@ function emitEditorUrlChangedPayload(payload) {
3276
3284
  var key = String(payload.url || '') + '|' + String(payload.password || '');
3277
3285
  if (key === lastEditorUrlPayloadKey) return;
3278
3286
  lastEditorUrlPayloadKey = key;
3287
+ try {
3288
+ console.info('[V2 iframe-url]', {
3289
+ url: payload.url || '',
3290
+ passwordPresent: !!payload.password,
3291
+ });
3292
+ } catch(_) {}
3279
3293
  send('editor-url-changed', payload);
3280
3294
  }
3281
3295
  function emitEditorUrlChanged(rawUrl) {
@@ -5048,6 +5062,67 @@ function stripDataVveInstanceSubtree(root) {
5048
5062
  }
5049
5063
  }
5050
5064
 
5065
+ function cssEscapeIdent(raw) {
5066
+ var s = raw == null ? '' : String(raw);
5067
+ if (!s) return '';
5068
+ try {
5069
+ if (typeof CSS !== 'undefined' && CSS && typeof CSS.escape === 'function') {
5070
+ return CSS.escape(s);
5071
+ }
5072
+ } catch(_) {}
5073
+ // Fallback escape for identifiers when CSS.escape is unavailable.
5074
+ return s.replace(/[^a-zA-Z0-9_-]/g, function(ch) { return '\\\\' + ch; });
5075
+ }
5076
+
5077
+ function unescapeCssToken(token) {
5078
+ if (!token) return '';
5079
+ var s = String(token);
5080
+ var out = '';
5081
+ for (var i = 0; i < s.length; i++) {
5082
+ var ch = s.charAt(i);
5083
+ if (ch === '\\\\' && i + 1 < s.length) {
5084
+ out += s.charAt(i + 1);
5085
+ i += 1;
5086
+ continue;
5087
+ }
5088
+ out += ch;
5089
+ }
5090
+ return out;
5091
+ }
5092
+
5093
+ function isGeneratedClassToken(token) {
5094
+ var t = token == null ? '' : String(token).trim();
5095
+ if (!t) return true;
5096
+ if (t.indexOf('vve-') === 0) return true;
5097
+ // Tailwind arbitrary values / variant-heavy utilities are often unstable in selectors.
5098
+ if (
5099
+ t.indexOf('[') !== -1 ||
5100
+ t.indexOf(']') !== -1 ||
5101
+ t.indexOf('(') !== -1 ||
5102
+ t.indexOf(')') !== -1 ||
5103
+ t.indexOf('{') !== -1 ||
5104
+ t.indexOf('}') !== -1 ||
5105
+ t.indexOf(':') !== -1
5106
+ ) return true;
5107
+ // CSS-in-JS / runtime hash prefixes.
5108
+ if (/^(css|jsx|sc|emotion|styled|chakra|mantine|mui|ant)-/i.test(t)) return true;
5109
+ // Classnames with long hashy suffixes (framework/runtime generated).
5110
+ if (/[a-f0-9]{8,}/i.test(t)) return true;
5111
+ if (/^[a-zA-Z_-]+[0-9]{4,}[a-zA-Z0-9_-]*$/.test(t)) return true;
5112
+ if (/^[a-zA-Z0-9_-]{36,}$/.test(t)) return true;
5113
+ return false;
5114
+ }
5115
+
5116
+ function escapeSelectorClassTokens(sel) {
5117
+ if (!sel || typeof sel !== 'string') return '';
5118
+ return sel.replace(/.((?:\\.|[^s>+~:#.])+)/g, function(_m, cls) {
5119
+ if (!cls) return _m;
5120
+ // Already escaped token; keep it as-is.
5121
+ if (cls.indexOf('\\\\') >= 0) return '.' + cls;
5122
+ return '.' + cssEscapeIdent(cls);
5123
+ });
5124
+ }
5125
+
5051
5126
  function buildSelector(el) {
5052
5127
  if (!el) return '';
5053
5128
  var doc = el.ownerDocument || document;
@@ -5059,16 +5134,16 @@ function buildSelector(el) {
5059
5134
  if (doc.querySelectorAll(attrSel).length === 1) return attrSel;
5060
5135
  } catch(_) {}
5061
5136
  }
5062
- if (el.id) return '#' + el.id;
5137
+ if (el.id) return '#' + cssEscapeIdent(el.id);
5063
5138
  var parts = [], node = el, depth = 0;
5064
5139
  while (node && node.nodeType === 1 && depth < 5) {
5065
- if (node.id) { parts.unshift('#' + node.id); break; }
5140
+ if (node.id) { parts.unshift('#' + cssEscapeIdent(node.id)); break; }
5066
5141
  var p = node.tagName.toLowerCase();
5067
5142
  if (node.classList && node.classList.length) {
5068
5143
  var clsArr = Array.from(node.classList).filter(function(c) {
5069
- return c.indexOf('vve-') !== 0;
5144
+ return c.indexOf('vve-') !== 0 && !isGeneratedClassToken(c);
5070
5145
  });
5071
- if (clsArr.length) p += '.' + clsArr.slice(0, 2).join('.');
5146
+ if (clsArr.length) p += '.' + clsArr.slice(0, 2).map(function(c) { return cssEscapeIdent(c); }).join('.');
5072
5147
  }
5073
5148
  var idx = 1, sib = node.previousElementSibling;
5074
5149
  while (sib) { if (sib.tagName === node.tagName) idx++; sib = sib.previousElementSibling; }
@@ -5080,17 +5155,32 @@ function buildSelector(el) {
5080
5155
  return parts.join(' > ');
5081
5156
  }
5082
5157
 
5158
+ function stripGeneratedSelectorClassTokens(sel) {
5159
+ if (!sel || typeof sel !== 'string') return '';
5160
+ var s = sel.replace(/.((?:\\.|[^s>+~:#.])+)/g, function(_m, cls) {
5161
+ var raw = unescapeCssToken(cls);
5162
+ if (isGeneratedClassToken(raw)) return '';
5163
+ return '.' + cssEscapeIdent(raw);
5164
+ });
5165
+ return s
5166
+ .replace(/.{2,}/g, '.')
5167
+ .replace(/s{2,}/g, ' ')
5168
+ .replace(/s*>s*>/g, ' > ')
5169
+ .trim();
5170
+ }
5171
+
5083
5172
  /**
5084
5173
  * Strip editor-only .vve-* class tokens from a selector string (fixes DB rows saved while an element was selected).
5085
5174
  */
5086
5175
  function sanitizeSelectorForMatch(sel) {
5087
5176
  if (!sel || typeof sel !== 'string') return '';
5088
5177
  var s0 = sel.replace(/.vve-[a-zA-Z0-9_-]+/gi, '');
5178
+ s0 = stripGeneratedSelectorClassTokens(s0);
5089
5179
  var parts = s0.split(/s*>s*/).map(function(seg) {
5090
5180
  var t = seg.replace(/.+/g, '.').replace(/.$/, '');
5091
5181
  return t.trim();
5092
5182
  });
5093
- return parts.filter(Boolean).join(' > ');
5183
+ return escapeSelectorClassTokens(parts.filter(Boolean).join(' > '));
5094
5184
  }
5095
5185
 
5096
5186
  /** Drop the rightmost :nth-of-type(n) (hydration / layout often shifts sibling indices). */
@@ -5134,11 +5224,12 @@ function querySelectorResolved(iframeDoc, selector) {
5134
5224
  return null;
5135
5225
  }
5136
5226
  var alt = sanitizeSelectorForMatch(selector);
5227
+ var escaped = escapeSelectorClassTokens(alt || selector);
5137
5228
  // Prefer sanitized + nth relax FIRST: raw selectors often still contain .vve-* from
5138
5229
  // save-time selection; those only match after clicking (we re-add vve-selected).
5139
- var el = walkRelax(alt || selector);
5230
+ var el = walkRelax(escaped || alt || selector);
5140
5231
  if (el) return el;
5141
- if (alt !== selector) {
5232
+ if (alt !== selector || escaped !== selector) {
5142
5233
  el = walkRelax(selector);
5143
5234
  if (el) return el;
5144
5235
  }
@@ -5805,6 +5896,12 @@ window.addEventListener('load', function() {
5805
5896
  if (!d || d.channel !== 'vvveb-proxy-url' || d.type !== 'editor-url-changed') return;
5806
5897
  if (!iframe || !iframe.contentWindow || ev.source !== iframe.contentWindow) return;
5807
5898
  var payload = d.payload || {};
5899
+ try {
5900
+ console.info('[V2 iframe-url bridge]', {
5901
+ url: payload.url || '',
5902
+ passwordPresent: !!payload.password,
5903
+ });
5904
+ } catch(_) {}
5808
5905
  emitEditorUrlChangedPayload({
5809
5906
  url: payload.url || undefined,
5810
5907
  password: payload.password || undefined,
@@ -6094,8 +6191,6 @@ function createVisualEditorMiddleware(options) {
6094
6191
  extraTrackingMarkersForRequest
6095
6192
  );
6096
6193
  const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
6097
- const proxyParam = (url.searchParams.get("proxy") || "").toLowerCase();
6098
- const useScraperProxy = proxyParam === "1" || proxyParam === "true" || proxyParam === "yes";
6099
6194
  const strictObserverFreezeForRequest = strictFreezeParam === "1" || strictFreezeParam === "true" || strictFreezeParam === "yes" ? true : strictFreezeParam === "0" || strictFreezeParam === "false" || strictFreezeParam === "no" ? false : strictObserverFreeze;
6100
6195
  if (!targetUrl) {
6101
6196
  res.statusCode = 400;
@@ -6105,40 +6200,7 @@ function createVisualEditorMiddleware(options) {
6105
6200
  const parsed = new URL(targetUrl);
6106
6201
  const origin = parsed.origin;
6107
6202
  const method = (req.method || "GET").toUpperCase();
6108
- const scraperProxyClient = useScraperProxy ? await getScraperProxyClient() : null;
6109
- if (useScraperProxy && !scraperProxyClient) {
6110
- res.statusCode = 500;
6111
- res.setHeader("Content-Type", "application/json");
6112
- res.end(
6113
- JSON.stringify({
6114
- error: "ScraperAPI proxy is not configured. Set SCRAPERAPI_PROXY_PASSWORD or SCRAPERAPI_API_KEY."
6115
- })
6116
- );
6117
- return;
6118
- }
6119
6203
  const directFetch = (input, init = {}) => fetch(input, init);
6120
- const scraperFetch = (input, init = {}) => {
6121
- if (!SCRAPER_PROXY_PASSWORD) return directFetch(input, init);
6122
- if (!useScraperProxy || !scraperProxyClient) {
6123
- const scraperUrl = new URL(SCRAPER_API_ENDPOINT);
6124
- scraperUrl.searchParams.set("api_key", SCRAPER_PROXY_PASSWORD);
6125
- scraperUrl.searchParams.set("url", input);
6126
- return fetch(scraperUrl.toString(), init);
6127
- }
6128
- return scraperProxyClient.fetchFn(input, {
6129
- ...init,
6130
- dispatcher: scraperProxyClient.dispatcher
6131
- });
6132
- };
6133
- const shouldFallbackFromScraper = async (resp) => {
6134
- try {
6135
- if (resp.ok) return false;
6136
- const text = await resp.clone().text();
6137
- return SCRAPER_BILLING_ERROR_RE.test(String(text || ""));
6138
- } catch (_) {
6139
- return false;
6140
- }
6141
- };
6142
6204
  const workerRawFetch = (input, init = {}) => {
6143
6205
  const workerUrl = new URL("/api/conversion-proxy", conversionProxyBaseUrlForRequest);
6144
6206
  workerUrl.searchParams.set("url", input);
@@ -6165,19 +6227,12 @@ function createVisualEditorMiddleware(options) {
6165
6227
  };
6166
6228
  const upstreamFetch = async (input, init = {}) => {
6167
6229
  if (conversionProxyBaseUrlForRequest) {
6230
+ const method2 = String(init?.method || "GET").toUpperCase();
6231
+ if (method2 !== "GET" && method2 !== "HEAD") {
6232
+ return directFetch(input, init);
6233
+ }
6168
6234
  return workerRawFetch(input, init);
6169
6235
  }
6170
- const primary = await scraperFetch(input, init);
6171
- if (!await shouldFallbackFromScraper(primary)) {
6172
- return primary;
6173
- }
6174
- try {
6175
- console.warn("[conversion-proxy] ScraperAPI billing/quota detected; falling back to direct fetch", {
6176
- url: input,
6177
- mode: useScraperProxy ? "proxy" : "simple"
6178
- });
6179
- } catch (_) {
6180
- }
6181
6236
  return directFetch(input, init);
6182
6237
  };
6183
6238
  const headers = {
@@ -6249,16 +6304,8 @@ function createVisualEditorMiddleware(options) {
6249
6304
  res.end(
6250
6305
  JSON.stringify({
6251
6306
  error: aborted ? `Upstream request timed out after ${upstreamTimeoutMs / 1e3}s` : fetchErr?.message || "Upstream fetch failed",
6252
- phase: useScraperProxy ? "scraperapi-proxy-fetch" : "scraperapi-simple-fetch",
6253
- fetchMode: useScraperProxy ? "proxy" : "simple",
6254
- scraperapi: {
6255
- host: SCRAPER_PROXY_HOST,
6256
- port: SCRAPER_PROXY_PORT,
6257
- username: SCRAPER_PROXY_USERNAME,
6258
- endpoint: SCRAPER_API_ENDPOINT,
6259
- hasProxyPassword: Boolean(SCRAPER_PROXY_PASSWORD),
6260
- requestTlsRejectUnauthorized: SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED
6261
- },
6307
+ phase: conversionProxyBaseUrlForRequest ? "worker-raw-fetch" : "direct-upstream-fetch",
6308
+ fetchMode: conversionProxyBaseUrlForRequest ? "worker" : "direct",
6262
6309
  cause: fetchCause && typeof fetchCause === "object" ? {
6263
6310
  name: fetchCause.name,
6264
6311
  code: fetchCause.code,
@@ -6444,8 +6491,51 @@ try{
6444
6491
  }
6445
6492
  }
6446
6493
  }catch(_){}
6447
- 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;}}
6448
- 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(_){}}
6494
+ function getEditorUrlPayload(){
6495
+ try{
6496
+ var u=new URL(window.location.href);
6497
+ var nested=u.searchParams.get("url");
6498
+ if(nested){
6499
+ return {url:nested,password:u.searchParams.get("password")||undefined};
6500
+ }
6501
+ var p=u.pathname||"";
6502
+ var isProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0||p.indexOf("api/conversion-proxy")!==-1;
6503
+ if(isProxyPath){
6504
+ var recoveredBase=new URL(TARGET_PAGE_URL,window.location.href);
6505
+ var qp=new URLSearchParams(u.search||"");
6506
+ qp.delete("url");
6507
+ qp.delete("password");
6508
+ qp.delete("conversionProxyBaseUrl");
6509
+ qp.delete("trackingMarkers");
6510
+ qp.delete("strictObserverFreeze");
6511
+ qp.delete("proxy");
6512
+ qp.delete("raw");
6513
+ recoveredBase.search="";
6514
+ qp.forEach(function(v,k){recoveredBase.searchParams.set(k,v);});
6515
+ recoveredBase.hash=u.hash||"";
6516
+ return {url:recoveredBase.toString(),password:u.searchParams.get("password")||undefined};
6517
+ }
6518
+ return {url:u.toString(),password:u.searchParams.get("password")||undefined};
6519
+ }catch(_){
6520
+ return null;
6521
+ }
6522
+ }
6523
+ function notifyEditorUrlChanged(){
6524
+ try{
6525
+ var payload=getEditorUrlPayload();
6526
+ if(!payload) return;
6527
+ try{
6528
+ console.info("[conversion-proxy] iframe url rendered",{
6529
+ current:window.location.href,
6530
+ target:payload.url||"",
6531
+ passwordPresent:!!payload.password
6532
+ });
6533
+ }catch(_){}
6534
+ if(window.parent){
6535
+ window.parent.postMessage({channel:PARENT_URL_CHANNEL,type:"editor-url-changed",payload:payload},"*");
6536
+ }
6537
+ }catch(_){}
6538
+ }
6449
6539
  try{notifyEditorUrlChanged();}catch(_){}
6450
6540
  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(_){}
6451
6541
  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(_){}
@@ -6453,7 +6543,29 @@ try{window.addEventListener("popstate",notifyEditorUrlChanged,true);}catch(_){}
6453
6543
  try{window.addEventListener("hashchange",notifyEditorUrlChanged,true);}catch(_){}
6454
6544
  function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
6455
6545
  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;}}
6456
- 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;var root="/api/conversion-proxy";return root+"?password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());}catch(_){return null;}}
6546
+ function toProxy(raw){
6547
+ if(isSkippable(raw))return null;
6548
+ var abs=toAbsolute(raw);
6549
+ if(!abs||typeof abs!=="string")return null;
6550
+ try{
6551
+ var parsed=new URL(abs);
6552
+ // If input is already a proxy URL, unwrap to its target url first
6553
+ // to avoid nested /api/conversion-proxy?url=/api/conversion-proxy?... chains.
6554
+ var p=(parsed.pathname||"");
6555
+ var isProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0||p.indexOf("api/conversion-proxy")!==-1;
6556
+ if(isProxyPath){
6557
+ var nested=parsed.searchParams.get("url")||"";
6558
+ if(nested){
6559
+ try{parsed=new URL(nested);}catch(_){}
6560
+ }
6561
+ }
6562
+ if(parsed.origin!==TARGET_ORIGIN)return null;
6563
+ var root="/api/conversion-proxy";
6564
+ return root+"?password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());
6565
+ }catch(_){
6566
+ return null;
6567
+ }
6568
+ }
6457
6569
  var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
6458
6570
  var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
6459
6571
  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;}}
@@ -6503,12 +6615,49 @@ var PROXY_BASE_URL=_proxyCtx?_proxyCtx.searchParams.get("conversionProxyBaseUrl"
6503
6615
  var PROXY_TRACKING_MARKERS=_proxyCtx?_proxyCtx.searchParams.get("trackingMarkers")||"":"";
6504
6616
  var PROXY_STRICT_FREEZE=_proxyCtx?_proxyCtx.searchParams.get("strictObserverFreeze")||"":"";
6505
6617
  var PROXY_UPSTREAM_MODE=_proxyCtx?_proxyCtx.searchParams.get("proxy")||"":"";
6618
+ var EDITOR_ORIGIN=(function(){try{return String(window.location.origin||"");}catch(_){return "";}})();
6619
+ var EDITOR_HOST_KEY=(function(){try{var u=new URL(EDITOR_ORIGIN);return (u.hostname||"").toLowerCase()+":"+(u.port||"");}catch(_){return "";}})();
6506
6620
  function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
6621
+ function isEditorHostUrl(u){
6622
+ try{
6623
+ if(!u) return false;
6624
+ var hostKey=(u.hostname||"").toLowerCase()+":"+(u.port||"");
6625
+ if(EDITOR_HOST_KEY&&hostKey===EDITOR_HOST_KEY) return true;
6626
+ // localhost aliases for same dev server port
6627
+ var host=(u.hostname||"").toLowerCase();
6628
+ var editorHost=EDITOR_HOST_KEY.split(":")[0]||"";
6629
+ var samePort=(u.port||"")===(EDITOR_HOST_KEY.split(":")[1]||"");
6630
+ var localAlias=(host==="localhost"||host==="127.0.0.1"||host==="[::1]");
6631
+ var editorLocalAlias=(editorHost==="localhost"||editorHost==="127.0.0.1"||editorHost==="[::1]");
6632
+ return samePort&&localAlias&&editorLocalAlias;
6633
+ }catch(_){
6634
+ return false;
6635
+ }
6636
+ }
6507
6637
  function toProxyNetworkUrl(raw){
6508
6638
  if(isSkippable(raw))return raw;
6509
6639
  try{
6510
6640
  var base=raw.startsWith("/")?TARGET_ORIGIN:TARGET_PAGE_URL;
6511
6641
  var abs=new URL(raw,base);
6642
+ // Unwrap already-proxied URLs first to avoid nested proxy urls.
6643
+ var p0=abs.pathname||"";
6644
+ var isProxyPath0=p0==="/api/conversion-proxy"||p0.indexOf("/api/conversion-proxy/")===0||p0.indexOf("api/conversion-proxy")!==-1;
6645
+ if(isProxyPath0){
6646
+ var nested0=abs.searchParams.get("url")||"";
6647
+ if(nested0){
6648
+ try{abs=new URL(nested0);}catch(_){}
6649
+ }
6650
+ }
6651
+ // Some embedded scripts build absolute requests against editor origin
6652
+ // (e.g. https://localhost:4001/api/unstable/graphql.json). Remap those
6653
+ // paths to target origin first, then proxy as usual.
6654
+ if(EDITOR_ORIGIN&&isEditorHostUrl(abs)){
6655
+ var p=abs.pathname||"";
6656
+ var isRootProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0;
6657
+ if(!isRootProxyPath){
6658
+ abs=new URL((abs.pathname||"/")+(abs.search||"")+(abs.hash||""),TARGET_ORIGIN);
6659
+ }
6660
+ }
6512
6661
  if(abs.origin!==TARGET_ORIGIN)return raw;
6513
6662
  var prox=new URL(PROXY_ROOT,window.location.origin);
6514
6663
  prox.searchParams.set("password",PROXY_PASSWORD||"");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@accelerated-agency/visual-editor",
3
- "version": "0.4.5",
3
+ "version": "0.4.7",
4
4
  "private": false,
5
5
  "description": "Conversion visual editor as a reusable React package",
6
6
  "type": "module",