@accelerated-agency/visual-editor 0.4.6 → 0.4.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/vite.cjs +231 -104
- package/dist/vite.js +231 -104
- 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,30 +108,6 @@ 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
111
|
var iframeAlwaysShowCss = `<style id="__ce_force_show">
|
|
150
112
|
|
|
151
113
|
</style>`;
|
|
@@ -3283,6 +3245,53 @@ function parseEditorUrlPayload(rawUrl) {
|
|
|
3283
3245
|
password: nestedPassword || undefined,
|
|
3284
3246
|
};
|
|
3285
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
|
+
}
|
|
3277
|
+
var fallbackUrl2 = (experimentData && experimentData.pageUrl) ? String(experimentData.pageUrl) : '';
|
|
3278
|
+
if (fallbackUrl2) {
|
|
3279
|
+
try {
|
|
3280
|
+
var targetBase = new URL(fallbackUrl2, window.location.href);
|
|
3281
|
+
if (parsed.origin !== targetBase.origin) {
|
|
3282
|
+
var normalized = new URL(parsed.pathname || '/', targetBase.origin);
|
|
3283
|
+
normalized.search = parsed.search || '';
|
|
3284
|
+
normalized.hash = parsed.hash || '';
|
|
3285
|
+
return {
|
|
3286
|
+
url: normalized.toString(),
|
|
3287
|
+
password:
|
|
3288
|
+
(experimentData && experimentData.editorPassword)
|
|
3289
|
+
? String(experimentData.editorPassword)
|
|
3290
|
+
: undefined,
|
|
3291
|
+
};
|
|
3292
|
+
}
|
|
3293
|
+
} catch(_) {}
|
|
3294
|
+
}
|
|
3286
3295
|
return {
|
|
3287
3296
|
url: parsed.toString(),
|
|
3288
3297
|
password:
|
|
@@ -3301,6 +3310,12 @@ function emitEditorUrlChangedPayload(payload) {
|
|
|
3301
3310
|
var key = String(payload.url || '') + '|' + String(payload.password || '');
|
|
3302
3311
|
if (key === lastEditorUrlPayloadKey) return;
|
|
3303
3312
|
lastEditorUrlPayloadKey = key;
|
|
3313
|
+
try {
|
|
3314
|
+
console.info('[V2 iframe-url]', {
|
|
3315
|
+
url: payload.url || '',
|
|
3316
|
+
passwordPresent: !!payload.password,
|
|
3317
|
+
});
|
|
3318
|
+
} catch(_) {}
|
|
3304
3319
|
send('editor-url-changed', payload);
|
|
3305
3320
|
}
|
|
3306
3321
|
function emitEditorUrlChanged(rawUrl) {
|
|
@@ -5073,6 +5088,67 @@ function stripDataVveInstanceSubtree(root) {
|
|
|
5073
5088
|
}
|
|
5074
5089
|
}
|
|
5075
5090
|
|
|
5091
|
+
function cssEscapeIdent(raw) {
|
|
5092
|
+
var s = raw == null ? '' : String(raw);
|
|
5093
|
+
if (!s) return '';
|
|
5094
|
+
try {
|
|
5095
|
+
if (typeof CSS !== 'undefined' && CSS && typeof CSS.escape === 'function') {
|
|
5096
|
+
return CSS.escape(s);
|
|
5097
|
+
}
|
|
5098
|
+
} catch(_) {}
|
|
5099
|
+
// Fallback escape for identifiers when CSS.escape is unavailable.
|
|
5100
|
+
return s.replace(/[^a-zA-Z0-9_-]/g, function(ch) { return '\\\\' + ch; });
|
|
5101
|
+
}
|
|
5102
|
+
|
|
5103
|
+
function unescapeCssToken(token) {
|
|
5104
|
+
if (!token) return '';
|
|
5105
|
+
var s = String(token);
|
|
5106
|
+
var out = '';
|
|
5107
|
+
for (var i = 0; i < s.length; i++) {
|
|
5108
|
+
var ch = s.charAt(i);
|
|
5109
|
+
if (ch === '\\\\' && i + 1 < s.length) {
|
|
5110
|
+
out += s.charAt(i + 1);
|
|
5111
|
+
i += 1;
|
|
5112
|
+
continue;
|
|
5113
|
+
}
|
|
5114
|
+
out += ch;
|
|
5115
|
+
}
|
|
5116
|
+
return out;
|
|
5117
|
+
}
|
|
5118
|
+
|
|
5119
|
+
function isGeneratedClassToken(token) {
|
|
5120
|
+
var t = token == null ? '' : String(token).trim();
|
|
5121
|
+
if (!t) return true;
|
|
5122
|
+
if (t.indexOf('vve-') === 0) return true;
|
|
5123
|
+
// Tailwind arbitrary values / variant-heavy utilities are often unstable in selectors.
|
|
5124
|
+
if (
|
|
5125
|
+
t.indexOf('[') !== -1 ||
|
|
5126
|
+
t.indexOf(']') !== -1 ||
|
|
5127
|
+
t.indexOf('(') !== -1 ||
|
|
5128
|
+
t.indexOf(')') !== -1 ||
|
|
5129
|
+
t.indexOf('{') !== -1 ||
|
|
5130
|
+
t.indexOf('}') !== -1 ||
|
|
5131
|
+
t.indexOf(':') !== -1
|
|
5132
|
+
) return true;
|
|
5133
|
+
// CSS-in-JS / runtime hash prefixes.
|
|
5134
|
+
if (/^(css|jsx|sc|emotion|styled|chakra|mantine|mui|ant)-/i.test(t)) return true;
|
|
5135
|
+
// Classnames with long hashy suffixes (framework/runtime generated).
|
|
5136
|
+
if (/[a-f0-9]{8,}/i.test(t)) return true;
|
|
5137
|
+
if (/^[a-zA-Z_-]+[0-9]{4,}[a-zA-Z0-9_-]*$/.test(t)) return true;
|
|
5138
|
+
if (/^[a-zA-Z0-9_-]{36,}$/.test(t)) return true;
|
|
5139
|
+
return false;
|
|
5140
|
+
}
|
|
5141
|
+
|
|
5142
|
+
function escapeSelectorClassTokens(sel) {
|
|
5143
|
+
if (!sel || typeof sel !== 'string') return '';
|
|
5144
|
+
return sel.replace(/.((?:\\.|[^s>+~:#.])+)/g, function(_m, cls) {
|
|
5145
|
+
if (!cls) return _m;
|
|
5146
|
+
// Already escaped token; keep it as-is.
|
|
5147
|
+
if (cls.indexOf('\\\\') >= 0) return '.' + cls;
|
|
5148
|
+
return '.' + cssEscapeIdent(cls);
|
|
5149
|
+
});
|
|
5150
|
+
}
|
|
5151
|
+
|
|
5076
5152
|
function buildSelector(el) {
|
|
5077
5153
|
if (!el) return '';
|
|
5078
5154
|
var doc = el.ownerDocument || document;
|
|
@@ -5084,16 +5160,16 @@ function buildSelector(el) {
|
|
|
5084
5160
|
if (doc.querySelectorAll(attrSel).length === 1) return attrSel;
|
|
5085
5161
|
} catch(_) {}
|
|
5086
5162
|
}
|
|
5087
|
-
if (el.id) return '#' + el.id;
|
|
5163
|
+
if (el.id) return '#' + cssEscapeIdent(el.id);
|
|
5088
5164
|
var parts = [], node = el, depth = 0;
|
|
5089
5165
|
while (node && node.nodeType === 1 && depth < 5) {
|
|
5090
|
-
if (node.id) { parts.unshift('#' + node.id); break; }
|
|
5166
|
+
if (node.id) { parts.unshift('#' + cssEscapeIdent(node.id)); break; }
|
|
5091
5167
|
var p = node.tagName.toLowerCase();
|
|
5092
5168
|
if (node.classList && node.classList.length) {
|
|
5093
5169
|
var clsArr = Array.from(node.classList).filter(function(c) {
|
|
5094
|
-
return c.indexOf('vve-') !== 0;
|
|
5170
|
+
return c.indexOf('vve-') !== 0 && !isGeneratedClassToken(c);
|
|
5095
5171
|
});
|
|
5096
|
-
if (clsArr.length) p += '.' + clsArr.slice(0, 2).join('.');
|
|
5172
|
+
if (clsArr.length) p += '.' + clsArr.slice(0, 2).map(function(c) { return cssEscapeIdent(c); }).join('.');
|
|
5097
5173
|
}
|
|
5098
5174
|
var idx = 1, sib = node.previousElementSibling;
|
|
5099
5175
|
while (sib) { if (sib.tagName === node.tagName) idx++; sib = sib.previousElementSibling; }
|
|
@@ -5105,17 +5181,32 @@ function buildSelector(el) {
|
|
|
5105
5181
|
return parts.join(' > ');
|
|
5106
5182
|
}
|
|
5107
5183
|
|
|
5184
|
+
function stripGeneratedSelectorClassTokens(sel) {
|
|
5185
|
+
if (!sel || typeof sel !== 'string') return '';
|
|
5186
|
+
var s = sel.replace(/.((?:\\.|[^s>+~:#.])+)/g, function(_m, cls) {
|
|
5187
|
+
var raw = unescapeCssToken(cls);
|
|
5188
|
+
if (isGeneratedClassToken(raw)) return '';
|
|
5189
|
+
return '.' + cssEscapeIdent(raw);
|
|
5190
|
+
});
|
|
5191
|
+
return s
|
|
5192
|
+
.replace(/.{2,}/g, '.')
|
|
5193
|
+
.replace(/s{2,}/g, ' ')
|
|
5194
|
+
.replace(/s*>s*>/g, ' > ')
|
|
5195
|
+
.trim();
|
|
5196
|
+
}
|
|
5197
|
+
|
|
5108
5198
|
/**
|
|
5109
5199
|
* Strip editor-only .vve-* class tokens from a selector string (fixes DB rows saved while an element was selected).
|
|
5110
5200
|
*/
|
|
5111
5201
|
function sanitizeSelectorForMatch(sel) {
|
|
5112
5202
|
if (!sel || typeof sel !== 'string') return '';
|
|
5113
5203
|
var s0 = sel.replace(/.vve-[a-zA-Z0-9_-]+/gi, '');
|
|
5204
|
+
s0 = stripGeneratedSelectorClassTokens(s0);
|
|
5114
5205
|
var parts = s0.split(/s*>s*/).map(function(seg) {
|
|
5115
5206
|
var t = seg.replace(/.+/g, '.').replace(/.$/, '');
|
|
5116
5207
|
return t.trim();
|
|
5117
5208
|
});
|
|
5118
|
-
return parts.filter(Boolean).join(' > ');
|
|
5209
|
+
return escapeSelectorClassTokens(parts.filter(Boolean).join(' > '));
|
|
5119
5210
|
}
|
|
5120
5211
|
|
|
5121
5212
|
/** Drop the rightmost :nth-of-type(n) (hydration / layout often shifts sibling indices). */
|
|
@@ -5159,11 +5250,12 @@ function querySelectorResolved(iframeDoc, selector) {
|
|
|
5159
5250
|
return null;
|
|
5160
5251
|
}
|
|
5161
5252
|
var alt = sanitizeSelectorForMatch(selector);
|
|
5253
|
+
var escaped = escapeSelectorClassTokens(alt || selector);
|
|
5162
5254
|
// Prefer sanitized + nth relax FIRST: raw selectors often still contain .vve-* from
|
|
5163
5255
|
// save-time selection; those only match after clicking (we re-add vve-selected).
|
|
5164
|
-
var el = walkRelax(alt || selector);
|
|
5256
|
+
var el = walkRelax(escaped || alt || selector);
|
|
5165
5257
|
if (el) return el;
|
|
5166
|
-
if (alt !== selector) {
|
|
5258
|
+
if (alt !== selector || escaped !== selector) {
|
|
5167
5259
|
el = walkRelax(selector);
|
|
5168
5260
|
if (el) return el;
|
|
5169
5261
|
}
|
|
@@ -5830,6 +5922,12 @@ window.addEventListener('load', function() {
|
|
|
5830
5922
|
if (!d || d.channel !== 'vvveb-proxy-url' || d.type !== 'editor-url-changed') return;
|
|
5831
5923
|
if (!iframe || !iframe.contentWindow || ev.source !== iframe.contentWindow) return;
|
|
5832
5924
|
var payload = d.payload || {};
|
|
5925
|
+
try {
|
|
5926
|
+
console.info('[V2 iframe-url bridge]', {
|
|
5927
|
+
url: payload.url || '',
|
|
5928
|
+
passwordPresent: !!payload.password,
|
|
5929
|
+
});
|
|
5930
|
+
} catch(_) {}
|
|
5833
5931
|
emitEditorUrlChangedPayload({
|
|
5834
5932
|
url: payload.url || undefined,
|
|
5835
5933
|
password: payload.password || undefined,
|
|
@@ -6119,8 +6217,6 @@ function createVisualEditorMiddleware(options) {
|
|
|
6119
6217
|
extraTrackingMarkersForRequest
|
|
6120
6218
|
);
|
|
6121
6219
|
const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
|
|
6122
|
-
const proxyParam = (url.searchParams.get("proxy") || "").toLowerCase();
|
|
6123
|
-
const useScraperProxy = proxyParam === "1" || proxyParam === "true" || proxyParam === "yes";
|
|
6124
6220
|
const strictObserverFreezeForRequest = strictFreezeParam === "1" || strictFreezeParam === "true" || strictFreezeParam === "yes" ? true : strictFreezeParam === "0" || strictFreezeParam === "false" || strictFreezeParam === "no" ? false : strictObserverFreeze;
|
|
6125
6221
|
if (!targetUrl) {
|
|
6126
6222
|
res.statusCode = 400;
|
|
@@ -6130,40 +6226,7 @@ function createVisualEditorMiddleware(options) {
|
|
|
6130
6226
|
const parsed = new URL(targetUrl);
|
|
6131
6227
|
const origin = parsed.origin;
|
|
6132
6228
|
const method = (req.method || "GET").toUpperCase();
|
|
6133
|
-
const scraperProxyClient = useScraperProxy ? await getScraperProxyClient() : null;
|
|
6134
|
-
if (useScraperProxy && !scraperProxyClient) {
|
|
6135
|
-
res.statusCode = 500;
|
|
6136
|
-
res.setHeader("Content-Type", "application/json");
|
|
6137
|
-
res.end(
|
|
6138
|
-
JSON.stringify({
|
|
6139
|
-
error: "ScraperAPI proxy is not configured. Set SCRAPERAPI_PROXY_PASSWORD or SCRAPERAPI_API_KEY."
|
|
6140
|
-
})
|
|
6141
|
-
);
|
|
6142
|
-
return;
|
|
6143
|
-
}
|
|
6144
6229
|
const directFetch = (input, init = {}) => fetch(input, init);
|
|
6145
|
-
const scraperFetch = (input, init = {}) => {
|
|
6146
|
-
if (!SCRAPER_PROXY_PASSWORD) return directFetch(input, init);
|
|
6147
|
-
if (!useScraperProxy || !scraperProxyClient) {
|
|
6148
|
-
const scraperUrl = new URL(SCRAPER_API_ENDPOINT);
|
|
6149
|
-
scraperUrl.searchParams.set("api_key", SCRAPER_PROXY_PASSWORD);
|
|
6150
|
-
scraperUrl.searchParams.set("url", input);
|
|
6151
|
-
return fetch(scraperUrl.toString(), init);
|
|
6152
|
-
}
|
|
6153
|
-
return scraperProxyClient.fetchFn(input, {
|
|
6154
|
-
...init,
|
|
6155
|
-
dispatcher: scraperProxyClient.dispatcher
|
|
6156
|
-
});
|
|
6157
|
-
};
|
|
6158
|
-
const shouldFallbackFromScraper = async (resp) => {
|
|
6159
|
-
try {
|
|
6160
|
-
if (resp.ok) return false;
|
|
6161
|
-
const text = await resp.clone().text();
|
|
6162
|
-
return SCRAPER_BILLING_ERROR_RE.test(String(text || ""));
|
|
6163
|
-
} catch (_) {
|
|
6164
|
-
return false;
|
|
6165
|
-
}
|
|
6166
|
-
};
|
|
6167
6230
|
const workerRawFetch = (input, init = {}) => {
|
|
6168
6231
|
const workerUrl = new URL("/api/conversion-proxy", conversionProxyBaseUrlForRequest);
|
|
6169
6232
|
workerUrl.searchParams.set("url", input);
|
|
@@ -6196,17 +6259,6 @@ function createVisualEditorMiddleware(options) {
|
|
|
6196
6259
|
}
|
|
6197
6260
|
return workerRawFetch(input, init);
|
|
6198
6261
|
}
|
|
6199
|
-
const primary = await scraperFetch(input, init);
|
|
6200
|
-
if (!await shouldFallbackFromScraper(primary)) {
|
|
6201
|
-
return primary;
|
|
6202
|
-
}
|
|
6203
|
-
try {
|
|
6204
|
-
console.warn("[conversion-proxy] ScraperAPI billing/quota detected; falling back to direct fetch", {
|
|
6205
|
-
url: input,
|
|
6206
|
-
mode: useScraperProxy ? "proxy" : "simple"
|
|
6207
|
-
});
|
|
6208
|
-
} catch (_) {
|
|
6209
|
-
}
|
|
6210
6262
|
return directFetch(input, init);
|
|
6211
6263
|
};
|
|
6212
6264
|
const headers = {
|
|
@@ -6278,16 +6330,8 @@ function createVisualEditorMiddleware(options) {
|
|
|
6278
6330
|
res.end(
|
|
6279
6331
|
JSON.stringify({
|
|
6280
6332
|
error: aborted ? `Upstream request timed out after ${upstreamTimeoutMs / 1e3}s` : fetchErr?.message || "Upstream fetch failed",
|
|
6281
|
-
phase:
|
|
6282
|
-
fetchMode:
|
|
6283
|
-
scraperapi: {
|
|
6284
|
-
host: SCRAPER_PROXY_HOST,
|
|
6285
|
-
port: SCRAPER_PROXY_PORT,
|
|
6286
|
-
username: SCRAPER_PROXY_USERNAME,
|
|
6287
|
-
endpoint: SCRAPER_API_ENDPOINT,
|
|
6288
|
-
hasProxyPassword: Boolean(SCRAPER_PROXY_PASSWORD),
|
|
6289
|
-
requestTlsRejectUnauthorized: SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED
|
|
6290
|
-
},
|
|
6333
|
+
phase: conversionProxyBaseUrlForRequest ? "worker-raw-fetch" : "direct-upstream-fetch",
|
|
6334
|
+
fetchMode: conversionProxyBaseUrlForRequest ? "worker" : "direct",
|
|
6291
6335
|
cause: fetchCause && typeof fetchCause === "object" ? {
|
|
6292
6336
|
name: fetchCause.name,
|
|
6293
6337
|
code: fetchCause.code,
|
|
@@ -6473,8 +6517,60 @@ try{
|
|
|
6473
6517
|
}
|
|
6474
6518
|
}
|
|
6475
6519
|
}catch(_){}
|
|
6476
|
-
function getEditorUrlPayload(){
|
|
6477
|
-
|
|
6520
|
+
function getEditorUrlPayload(){
|
|
6521
|
+
try{
|
|
6522
|
+
var u=new URL(window.location.href);
|
|
6523
|
+
var nested=u.searchParams.get("url");
|
|
6524
|
+
if(nested){
|
|
6525
|
+
return {url:nested,password:u.searchParams.get("password")||undefined};
|
|
6526
|
+
}
|
|
6527
|
+
var p=u.pathname||"";
|
|
6528
|
+
var isProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0||p.indexOf("api/conversion-proxy")!==-1;
|
|
6529
|
+
if(isProxyPath){
|
|
6530
|
+
var recoveredBase=new URL(TARGET_PAGE_URL,window.location.href);
|
|
6531
|
+
var qp=new URLSearchParams(u.search||"");
|
|
6532
|
+
qp.delete("url");
|
|
6533
|
+
qp.delete("password");
|
|
6534
|
+
qp.delete("conversionProxyBaseUrl");
|
|
6535
|
+
qp.delete("trackingMarkers");
|
|
6536
|
+
qp.delete("strictObserverFreeze");
|
|
6537
|
+
qp.delete("proxy");
|
|
6538
|
+
qp.delete("raw");
|
|
6539
|
+
recoveredBase.search="";
|
|
6540
|
+
qp.forEach(function(v,k){recoveredBase.searchParams.set(k,v);});
|
|
6541
|
+
recoveredBase.hash=u.hash||"";
|
|
6542
|
+
return {url:recoveredBase.toString(),password:u.searchParams.get("password")||undefined};
|
|
6543
|
+
}
|
|
6544
|
+
try{
|
|
6545
|
+
var targetBase2=new URL(TARGET_PAGE_URL,window.location.href);
|
|
6546
|
+
if(u.origin!==targetBase2.origin){
|
|
6547
|
+
var normalized2=new URL((u.pathname||"/"),targetBase2.origin);
|
|
6548
|
+
normalized2.search=u.search||"";
|
|
6549
|
+
normalized2.hash=u.hash||"";
|
|
6550
|
+
return {url:normalized2.toString(),password:u.searchParams.get("password")||undefined};
|
|
6551
|
+
}
|
|
6552
|
+
}catch(_){}
|
|
6553
|
+
return {url:u.toString(),password:u.searchParams.get("password")||undefined};
|
|
6554
|
+
}catch(_){
|
|
6555
|
+
return null;
|
|
6556
|
+
}
|
|
6557
|
+
}
|
|
6558
|
+
function notifyEditorUrlChanged(){
|
|
6559
|
+
try{
|
|
6560
|
+
var payload=getEditorUrlPayload();
|
|
6561
|
+
if(!payload) return;
|
|
6562
|
+
try{
|
|
6563
|
+
console.info("[conversion-proxy] iframe url rendered",{
|
|
6564
|
+
current:window.location.href,
|
|
6565
|
+
target:payload.url||"",
|
|
6566
|
+
passwordPresent:!!payload.password
|
|
6567
|
+
});
|
|
6568
|
+
}catch(_){}
|
|
6569
|
+
if(window.parent){
|
|
6570
|
+
window.parent.postMessage({channel:PARENT_URL_CHANNEL,type:"editor-url-changed",payload:payload},"*");
|
|
6571
|
+
}
|
|
6572
|
+
}catch(_){}
|
|
6573
|
+
}
|
|
6478
6574
|
try{notifyEditorUrlChanged();}catch(_){}
|
|
6479
6575
|
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(_){}
|
|
6480
6576
|
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(_){}
|
|
@@ -6482,7 +6578,29 @@ try{window.addEventListener("popstate",notifyEditorUrlChanged,true);}catch(_){}
|
|
|
6482
6578
|
try{window.addEventListener("hashchange",notifyEditorUrlChanged,true);}catch(_){}
|
|
6483
6579
|
function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
|
|
6484
6580
|
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;}}
|
|
6485
|
-
function toProxy(raw){
|
|
6581
|
+
function toProxy(raw){
|
|
6582
|
+
if(isSkippable(raw))return null;
|
|
6583
|
+
var abs=toAbsolute(raw);
|
|
6584
|
+
if(!abs||typeof abs!=="string")return null;
|
|
6585
|
+
try{
|
|
6586
|
+
var parsed=new URL(abs);
|
|
6587
|
+
// If input is already a proxy URL, unwrap to its target url first
|
|
6588
|
+
// to avoid nested /api/conversion-proxy?url=/api/conversion-proxy?... chains.
|
|
6589
|
+
var p=(parsed.pathname||"");
|
|
6590
|
+
var isProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0||p.indexOf("api/conversion-proxy")!==-1;
|
|
6591
|
+
if(isProxyPath){
|
|
6592
|
+
var nested=parsed.searchParams.get("url")||"";
|
|
6593
|
+
if(nested){
|
|
6594
|
+
try{parsed=new URL(nested);}catch(_){}
|
|
6595
|
+
}
|
|
6596
|
+
}
|
|
6597
|
+
if(parsed.origin!==TARGET_ORIGIN)return null;
|
|
6598
|
+
var root="/api/conversion-proxy";
|
|
6599
|
+
return root+"?password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());
|
|
6600
|
+
}catch(_){
|
|
6601
|
+
return null;
|
|
6602
|
+
}
|
|
6603
|
+
}
|
|
6486
6604
|
var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
|
|
6487
6605
|
var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
|
|
6488
6606
|
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;}}
|
|
@@ -6556,6 +6674,15 @@ function toProxyNetworkUrl(raw){
|
|
|
6556
6674
|
try{
|
|
6557
6675
|
var base=raw.startsWith("/")?TARGET_ORIGIN:TARGET_PAGE_URL;
|
|
6558
6676
|
var abs=new URL(raw,base);
|
|
6677
|
+
// Unwrap already-proxied URLs first to avoid nested proxy urls.
|
|
6678
|
+
var p0=abs.pathname||"";
|
|
6679
|
+
var isProxyPath0=p0==="/api/conversion-proxy"||p0.indexOf("/api/conversion-proxy/")===0||p0.indexOf("api/conversion-proxy")!==-1;
|
|
6680
|
+
if(isProxyPath0){
|
|
6681
|
+
var nested0=abs.searchParams.get("url")||"";
|
|
6682
|
+
if(nested0){
|
|
6683
|
+
try{abs=new URL(nested0);}catch(_){}
|
|
6684
|
+
}
|
|
6685
|
+
}
|
|
6559
6686
|
// Some embedded scripts build absolute requests against editor origin
|
|
6560
6687
|
// (e.g. https://localhost:4001/api/unstable/graphql.json). Remap those
|
|
6561
6688
|
// paths to target origin first, then proxy as usual.
|
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,30 +100,6 @@ 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
103
|
var iframeAlwaysShowCss = `<style id="__ce_force_show">
|
|
142
104
|
|
|
143
105
|
</style>`;
|
|
@@ -3275,6 +3237,53 @@ function parseEditorUrlPayload(rawUrl) {
|
|
|
3275
3237
|
password: nestedPassword || undefined,
|
|
3276
3238
|
};
|
|
3277
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
|
+
}
|
|
3269
|
+
var fallbackUrl2 = (experimentData && experimentData.pageUrl) ? String(experimentData.pageUrl) : '';
|
|
3270
|
+
if (fallbackUrl2) {
|
|
3271
|
+
try {
|
|
3272
|
+
var targetBase = new URL(fallbackUrl2, window.location.href);
|
|
3273
|
+
if (parsed.origin !== targetBase.origin) {
|
|
3274
|
+
var normalized = new URL(parsed.pathname || '/', targetBase.origin);
|
|
3275
|
+
normalized.search = parsed.search || '';
|
|
3276
|
+
normalized.hash = parsed.hash || '';
|
|
3277
|
+
return {
|
|
3278
|
+
url: normalized.toString(),
|
|
3279
|
+
password:
|
|
3280
|
+
(experimentData && experimentData.editorPassword)
|
|
3281
|
+
? String(experimentData.editorPassword)
|
|
3282
|
+
: undefined,
|
|
3283
|
+
};
|
|
3284
|
+
}
|
|
3285
|
+
} catch(_) {}
|
|
3286
|
+
}
|
|
3278
3287
|
return {
|
|
3279
3288
|
url: parsed.toString(),
|
|
3280
3289
|
password:
|
|
@@ -3293,6 +3302,12 @@ function emitEditorUrlChangedPayload(payload) {
|
|
|
3293
3302
|
var key = String(payload.url || '') + '|' + String(payload.password || '');
|
|
3294
3303
|
if (key === lastEditorUrlPayloadKey) return;
|
|
3295
3304
|
lastEditorUrlPayloadKey = key;
|
|
3305
|
+
try {
|
|
3306
|
+
console.info('[V2 iframe-url]', {
|
|
3307
|
+
url: payload.url || '',
|
|
3308
|
+
passwordPresent: !!payload.password,
|
|
3309
|
+
});
|
|
3310
|
+
} catch(_) {}
|
|
3296
3311
|
send('editor-url-changed', payload);
|
|
3297
3312
|
}
|
|
3298
3313
|
function emitEditorUrlChanged(rawUrl) {
|
|
@@ -5065,6 +5080,67 @@ function stripDataVveInstanceSubtree(root) {
|
|
|
5065
5080
|
}
|
|
5066
5081
|
}
|
|
5067
5082
|
|
|
5083
|
+
function cssEscapeIdent(raw) {
|
|
5084
|
+
var s = raw == null ? '' : String(raw);
|
|
5085
|
+
if (!s) return '';
|
|
5086
|
+
try {
|
|
5087
|
+
if (typeof CSS !== 'undefined' && CSS && typeof CSS.escape === 'function') {
|
|
5088
|
+
return CSS.escape(s);
|
|
5089
|
+
}
|
|
5090
|
+
} catch(_) {}
|
|
5091
|
+
// Fallback escape for identifiers when CSS.escape is unavailable.
|
|
5092
|
+
return s.replace(/[^a-zA-Z0-9_-]/g, function(ch) { return '\\\\' + ch; });
|
|
5093
|
+
}
|
|
5094
|
+
|
|
5095
|
+
function unescapeCssToken(token) {
|
|
5096
|
+
if (!token) return '';
|
|
5097
|
+
var s = String(token);
|
|
5098
|
+
var out = '';
|
|
5099
|
+
for (var i = 0; i < s.length; i++) {
|
|
5100
|
+
var ch = s.charAt(i);
|
|
5101
|
+
if (ch === '\\\\' && i + 1 < s.length) {
|
|
5102
|
+
out += s.charAt(i + 1);
|
|
5103
|
+
i += 1;
|
|
5104
|
+
continue;
|
|
5105
|
+
}
|
|
5106
|
+
out += ch;
|
|
5107
|
+
}
|
|
5108
|
+
return out;
|
|
5109
|
+
}
|
|
5110
|
+
|
|
5111
|
+
function isGeneratedClassToken(token) {
|
|
5112
|
+
var t = token == null ? '' : String(token).trim();
|
|
5113
|
+
if (!t) return true;
|
|
5114
|
+
if (t.indexOf('vve-') === 0) return true;
|
|
5115
|
+
// Tailwind arbitrary values / variant-heavy utilities are often unstable in selectors.
|
|
5116
|
+
if (
|
|
5117
|
+
t.indexOf('[') !== -1 ||
|
|
5118
|
+
t.indexOf(']') !== -1 ||
|
|
5119
|
+
t.indexOf('(') !== -1 ||
|
|
5120
|
+
t.indexOf(')') !== -1 ||
|
|
5121
|
+
t.indexOf('{') !== -1 ||
|
|
5122
|
+
t.indexOf('}') !== -1 ||
|
|
5123
|
+
t.indexOf(':') !== -1
|
|
5124
|
+
) return true;
|
|
5125
|
+
// CSS-in-JS / runtime hash prefixes.
|
|
5126
|
+
if (/^(css|jsx|sc|emotion|styled|chakra|mantine|mui|ant)-/i.test(t)) return true;
|
|
5127
|
+
// Classnames with long hashy suffixes (framework/runtime generated).
|
|
5128
|
+
if (/[a-f0-9]{8,}/i.test(t)) return true;
|
|
5129
|
+
if (/^[a-zA-Z_-]+[0-9]{4,}[a-zA-Z0-9_-]*$/.test(t)) return true;
|
|
5130
|
+
if (/^[a-zA-Z0-9_-]{36,}$/.test(t)) return true;
|
|
5131
|
+
return false;
|
|
5132
|
+
}
|
|
5133
|
+
|
|
5134
|
+
function escapeSelectorClassTokens(sel) {
|
|
5135
|
+
if (!sel || typeof sel !== 'string') return '';
|
|
5136
|
+
return sel.replace(/.((?:\\.|[^s>+~:#.])+)/g, function(_m, cls) {
|
|
5137
|
+
if (!cls) return _m;
|
|
5138
|
+
// Already escaped token; keep it as-is.
|
|
5139
|
+
if (cls.indexOf('\\\\') >= 0) return '.' + cls;
|
|
5140
|
+
return '.' + cssEscapeIdent(cls);
|
|
5141
|
+
});
|
|
5142
|
+
}
|
|
5143
|
+
|
|
5068
5144
|
function buildSelector(el) {
|
|
5069
5145
|
if (!el) return '';
|
|
5070
5146
|
var doc = el.ownerDocument || document;
|
|
@@ -5076,16 +5152,16 @@ function buildSelector(el) {
|
|
|
5076
5152
|
if (doc.querySelectorAll(attrSel).length === 1) return attrSel;
|
|
5077
5153
|
} catch(_) {}
|
|
5078
5154
|
}
|
|
5079
|
-
if (el.id) return '#' + el.id;
|
|
5155
|
+
if (el.id) return '#' + cssEscapeIdent(el.id);
|
|
5080
5156
|
var parts = [], node = el, depth = 0;
|
|
5081
5157
|
while (node && node.nodeType === 1 && depth < 5) {
|
|
5082
|
-
if (node.id) { parts.unshift('#' + node.id); break; }
|
|
5158
|
+
if (node.id) { parts.unshift('#' + cssEscapeIdent(node.id)); break; }
|
|
5083
5159
|
var p = node.tagName.toLowerCase();
|
|
5084
5160
|
if (node.classList && node.classList.length) {
|
|
5085
5161
|
var clsArr = Array.from(node.classList).filter(function(c) {
|
|
5086
|
-
return c.indexOf('vve-') !== 0;
|
|
5162
|
+
return c.indexOf('vve-') !== 0 && !isGeneratedClassToken(c);
|
|
5087
5163
|
});
|
|
5088
|
-
if (clsArr.length) p += '.' + clsArr.slice(0, 2).join('.');
|
|
5164
|
+
if (clsArr.length) p += '.' + clsArr.slice(0, 2).map(function(c) { return cssEscapeIdent(c); }).join('.');
|
|
5089
5165
|
}
|
|
5090
5166
|
var idx = 1, sib = node.previousElementSibling;
|
|
5091
5167
|
while (sib) { if (sib.tagName === node.tagName) idx++; sib = sib.previousElementSibling; }
|
|
@@ -5097,17 +5173,32 @@ function buildSelector(el) {
|
|
|
5097
5173
|
return parts.join(' > ');
|
|
5098
5174
|
}
|
|
5099
5175
|
|
|
5176
|
+
function stripGeneratedSelectorClassTokens(sel) {
|
|
5177
|
+
if (!sel || typeof sel !== 'string') return '';
|
|
5178
|
+
var s = sel.replace(/.((?:\\.|[^s>+~:#.])+)/g, function(_m, cls) {
|
|
5179
|
+
var raw = unescapeCssToken(cls);
|
|
5180
|
+
if (isGeneratedClassToken(raw)) return '';
|
|
5181
|
+
return '.' + cssEscapeIdent(raw);
|
|
5182
|
+
});
|
|
5183
|
+
return s
|
|
5184
|
+
.replace(/.{2,}/g, '.')
|
|
5185
|
+
.replace(/s{2,}/g, ' ')
|
|
5186
|
+
.replace(/s*>s*>/g, ' > ')
|
|
5187
|
+
.trim();
|
|
5188
|
+
}
|
|
5189
|
+
|
|
5100
5190
|
/**
|
|
5101
5191
|
* Strip editor-only .vve-* class tokens from a selector string (fixes DB rows saved while an element was selected).
|
|
5102
5192
|
*/
|
|
5103
5193
|
function sanitizeSelectorForMatch(sel) {
|
|
5104
5194
|
if (!sel || typeof sel !== 'string') return '';
|
|
5105
5195
|
var s0 = sel.replace(/.vve-[a-zA-Z0-9_-]+/gi, '');
|
|
5196
|
+
s0 = stripGeneratedSelectorClassTokens(s0);
|
|
5106
5197
|
var parts = s0.split(/s*>s*/).map(function(seg) {
|
|
5107
5198
|
var t = seg.replace(/.+/g, '.').replace(/.$/, '');
|
|
5108
5199
|
return t.trim();
|
|
5109
5200
|
});
|
|
5110
|
-
return parts.filter(Boolean).join(' > ');
|
|
5201
|
+
return escapeSelectorClassTokens(parts.filter(Boolean).join(' > '));
|
|
5111
5202
|
}
|
|
5112
5203
|
|
|
5113
5204
|
/** Drop the rightmost :nth-of-type(n) (hydration / layout often shifts sibling indices). */
|
|
@@ -5151,11 +5242,12 @@ function querySelectorResolved(iframeDoc, selector) {
|
|
|
5151
5242
|
return null;
|
|
5152
5243
|
}
|
|
5153
5244
|
var alt = sanitizeSelectorForMatch(selector);
|
|
5245
|
+
var escaped = escapeSelectorClassTokens(alt || selector);
|
|
5154
5246
|
// Prefer sanitized + nth relax FIRST: raw selectors often still contain .vve-* from
|
|
5155
5247
|
// save-time selection; those only match after clicking (we re-add vve-selected).
|
|
5156
|
-
var el = walkRelax(alt || selector);
|
|
5248
|
+
var el = walkRelax(escaped || alt || selector);
|
|
5157
5249
|
if (el) return el;
|
|
5158
|
-
if (alt !== selector) {
|
|
5250
|
+
if (alt !== selector || escaped !== selector) {
|
|
5159
5251
|
el = walkRelax(selector);
|
|
5160
5252
|
if (el) return el;
|
|
5161
5253
|
}
|
|
@@ -5822,6 +5914,12 @@ window.addEventListener('load', function() {
|
|
|
5822
5914
|
if (!d || d.channel !== 'vvveb-proxy-url' || d.type !== 'editor-url-changed') return;
|
|
5823
5915
|
if (!iframe || !iframe.contentWindow || ev.source !== iframe.contentWindow) return;
|
|
5824
5916
|
var payload = d.payload || {};
|
|
5917
|
+
try {
|
|
5918
|
+
console.info('[V2 iframe-url bridge]', {
|
|
5919
|
+
url: payload.url || '',
|
|
5920
|
+
passwordPresent: !!payload.password,
|
|
5921
|
+
});
|
|
5922
|
+
} catch(_) {}
|
|
5825
5923
|
emitEditorUrlChangedPayload({
|
|
5826
5924
|
url: payload.url || undefined,
|
|
5827
5925
|
password: payload.password || undefined,
|
|
@@ -6111,8 +6209,6 @@ function createVisualEditorMiddleware(options) {
|
|
|
6111
6209
|
extraTrackingMarkersForRequest
|
|
6112
6210
|
);
|
|
6113
6211
|
const strictFreezeParam = (url.searchParams.get("strictObserverFreeze") || "").toLowerCase();
|
|
6114
|
-
const proxyParam = (url.searchParams.get("proxy") || "").toLowerCase();
|
|
6115
|
-
const useScraperProxy = proxyParam === "1" || proxyParam === "true" || proxyParam === "yes";
|
|
6116
6212
|
const strictObserverFreezeForRequest = strictFreezeParam === "1" || strictFreezeParam === "true" || strictFreezeParam === "yes" ? true : strictFreezeParam === "0" || strictFreezeParam === "false" || strictFreezeParam === "no" ? false : strictObserverFreeze;
|
|
6117
6213
|
if (!targetUrl) {
|
|
6118
6214
|
res.statusCode = 400;
|
|
@@ -6122,40 +6218,7 @@ function createVisualEditorMiddleware(options) {
|
|
|
6122
6218
|
const parsed = new URL(targetUrl);
|
|
6123
6219
|
const origin = parsed.origin;
|
|
6124
6220
|
const method = (req.method || "GET").toUpperCase();
|
|
6125
|
-
const scraperProxyClient = useScraperProxy ? await getScraperProxyClient() : null;
|
|
6126
|
-
if (useScraperProxy && !scraperProxyClient) {
|
|
6127
|
-
res.statusCode = 500;
|
|
6128
|
-
res.setHeader("Content-Type", "application/json");
|
|
6129
|
-
res.end(
|
|
6130
|
-
JSON.stringify({
|
|
6131
|
-
error: "ScraperAPI proxy is not configured. Set SCRAPERAPI_PROXY_PASSWORD or SCRAPERAPI_API_KEY."
|
|
6132
|
-
})
|
|
6133
|
-
);
|
|
6134
|
-
return;
|
|
6135
|
-
}
|
|
6136
6221
|
const directFetch = (input, init = {}) => fetch(input, init);
|
|
6137
|
-
const scraperFetch = (input, init = {}) => {
|
|
6138
|
-
if (!SCRAPER_PROXY_PASSWORD) return directFetch(input, init);
|
|
6139
|
-
if (!useScraperProxy || !scraperProxyClient) {
|
|
6140
|
-
const scraperUrl = new URL(SCRAPER_API_ENDPOINT);
|
|
6141
|
-
scraperUrl.searchParams.set("api_key", SCRAPER_PROXY_PASSWORD);
|
|
6142
|
-
scraperUrl.searchParams.set("url", input);
|
|
6143
|
-
return fetch(scraperUrl.toString(), init);
|
|
6144
|
-
}
|
|
6145
|
-
return scraperProxyClient.fetchFn(input, {
|
|
6146
|
-
...init,
|
|
6147
|
-
dispatcher: scraperProxyClient.dispatcher
|
|
6148
|
-
});
|
|
6149
|
-
};
|
|
6150
|
-
const shouldFallbackFromScraper = async (resp) => {
|
|
6151
|
-
try {
|
|
6152
|
-
if (resp.ok) return false;
|
|
6153
|
-
const text = await resp.clone().text();
|
|
6154
|
-
return SCRAPER_BILLING_ERROR_RE.test(String(text || ""));
|
|
6155
|
-
} catch (_) {
|
|
6156
|
-
return false;
|
|
6157
|
-
}
|
|
6158
|
-
};
|
|
6159
6222
|
const workerRawFetch = (input, init = {}) => {
|
|
6160
6223
|
const workerUrl = new URL("/api/conversion-proxy", conversionProxyBaseUrlForRequest);
|
|
6161
6224
|
workerUrl.searchParams.set("url", input);
|
|
@@ -6188,17 +6251,6 @@ function createVisualEditorMiddleware(options) {
|
|
|
6188
6251
|
}
|
|
6189
6252
|
return workerRawFetch(input, init);
|
|
6190
6253
|
}
|
|
6191
|
-
const primary = await scraperFetch(input, init);
|
|
6192
|
-
if (!await shouldFallbackFromScraper(primary)) {
|
|
6193
|
-
return primary;
|
|
6194
|
-
}
|
|
6195
|
-
try {
|
|
6196
|
-
console.warn("[conversion-proxy] ScraperAPI billing/quota detected; falling back to direct fetch", {
|
|
6197
|
-
url: input,
|
|
6198
|
-
mode: useScraperProxy ? "proxy" : "simple"
|
|
6199
|
-
});
|
|
6200
|
-
} catch (_) {
|
|
6201
|
-
}
|
|
6202
6254
|
return directFetch(input, init);
|
|
6203
6255
|
};
|
|
6204
6256
|
const headers = {
|
|
@@ -6270,16 +6322,8 @@ function createVisualEditorMiddleware(options) {
|
|
|
6270
6322
|
res.end(
|
|
6271
6323
|
JSON.stringify({
|
|
6272
6324
|
error: aborted ? `Upstream request timed out after ${upstreamTimeoutMs / 1e3}s` : fetchErr?.message || "Upstream fetch failed",
|
|
6273
|
-
phase:
|
|
6274
|
-
fetchMode:
|
|
6275
|
-
scraperapi: {
|
|
6276
|
-
host: SCRAPER_PROXY_HOST,
|
|
6277
|
-
port: SCRAPER_PROXY_PORT,
|
|
6278
|
-
username: SCRAPER_PROXY_USERNAME,
|
|
6279
|
-
endpoint: SCRAPER_API_ENDPOINT,
|
|
6280
|
-
hasProxyPassword: Boolean(SCRAPER_PROXY_PASSWORD),
|
|
6281
|
-
requestTlsRejectUnauthorized: SCRAPER_REQUEST_TLS_REJECT_UNAUTHORIZED
|
|
6282
|
-
},
|
|
6325
|
+
phase: conversionProxyBaseUrlForRequest ? "worker-raw-fetch" : "direct-upstream-fetch",
|
|
6326
|
+
fetchMode: conversionProxyBaseUrlForRequest ? "worker" : "direct",
|
|
6283
6327
|
cause: fetchCause && typeof fetchCause === "object" ? {
|
|
6284
6328
|
name: fetchCause.name,
|
|
6285
6329
|
code: fetchCause.code,
|
|
@@ -6465,8 +6509,60 @@ try{
|
|
|
6465
6509
|
}
|
|
6466
6510
|
}
|
|
6467
6511
|
}catch(_){}
|
|
6468
|
-
function getEditorUrlPayload(){
|
|
6469
|
-
|
|
6512
|
+
function getEditorUrlPayload(){
|
|
6513
|
+
try{
|
|
6514
|
+
var u=new URL(window.location.href);
|
|
6515
|
+
var nested=u.searchParams.get("url");
|
|
6516
|
+
if(nested){
|
|
6517
|
+
return {url:nested,password:u.searchParams.get("password")||undefined};
|
|
6518
|
+
}
|
|
6519
|
+
var p=u.pathname||"";
|
|
6520
|
+
var isProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0||p.indexOf("api/conversion-proxy")!==-1;
|
|
6521
|
+
if(isProxyPath){
|
|
6522
|
+
var recoveredBase=new URL(TARGET_PAGE_URL,window.location.href);
|
|
6523
|
+
var qp=new URLSearchParams(u.search||"");
|
|
6524
|
+
qp.delete("url");
|
|
6525
|
+
qp.delete("password");
|
|
6526
|
+
qp.delete("conversionProxyBaseUrl");
|
|
6527
|
+
qp.delete("trackingMarkers");
|
|
6528
|
+
qp.delete("strictObserverFreeze");
|
|
6529
|
+
qp.delete("proxy");
|
|
6530
|
+
qp.delete("raw");
|
|
6531
|
+
recoveredBase.search="";
|
|
6532
|
+
qp.forEach(function(v,k){recoveredBase.searchParams.set(k,v);});
|
|
6533
|
+
recoveredBase.hash=u.hash||"";
|
|
6534
|
+
return {url:recoveredBase.toString(),password:u.searchParams.get("password")||undefined};
|
|
6535
|
+
}
|
|
6536
|
+
try{
|
|
6537
|
+
var targetBase2=new URL(TARGET_PAGE_URL,window.location.href);
|
|
6538
|
+
if(u.origin!==targetBase2.origin){
|
|
6539
|
+
var normalized2=new URL((u.pathname||"/"),targetBase2.origin);
|
|
6540
|
+
normalized2.search=u.search||"";
|
|
6541
|
+
normalized2.hash=u.hash||"";
|
|
6542
|
+
return {url:normalized2.toString(),password:u.searchParams.get("password")||undefined};
|
|
6543
|
+
}
|
|
6544
|
+
}catch(_){}
|
|
6545
|
+
return {url:u.toString(),password:u.searchParams.get("password")||undefined};
|
|
6546
|
+
}catch(_){
|
|
6547
|
+
return null;
|
|
6548
|
+
}
|
|
6549
|
+
}
|
|
6550
|
+
function notifyEditorUrlChanged(){
|
|
6551
|
+
try{
|
|
6552
|
+
var payload=getEditorUrlPayload();
|
|
6553
|
+
if(!payload) return;
|
|
6554
|
+
try{
|
|
6555
|
+
console.info("[conversion-proxy] iframe url rendered",{
|
|
6556
|
+
current:window.location.href,
|
|
6557
|
+
target:payload.url||"",
|
|
6558
|
+
passwordPresent:!!payload.password
|
|
6559
|
+
});
|
|
6560
|
+
}catch(_){}
|
|
6561
|
+
if(window.parent){
|
|
6562
|
+
window.parent.postMessage({channel:PARENT_URL_CHANNEL,type:"editor-url-changed",payload:payload},"*");
|
|
6563
|
+
}
|
|
6564
|
+
}catch(_){}
|
|
6565
|
+
}
|
|
6470
6566
|
try{notifyEditorUrlChanged();}catch(_){}
|
|
6471
6567
|
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(_){}
|
|
6472
6568
|
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(_){}
|
|
@@ -6474,7 +6570,29 @@ try{window.addEventListener("popstate",notifyEditorUrlChanged,true);}catch(_){}
|
|
|
6474
6570
|
try{window.addEventListener("hashchange",notifyEditorUrlChanged,true);}catch(_){}
|
|
6475
6571
|
function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}
|
|
6476
6572
|
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;}}
|
|
6477
|
-
function toProxy(raw){
|
|
6573
|
+
function toProxy(raw){
|
|
6574
|
+
if(isSkippable(raw))return null;
|
|
6575
|
+
var abs=toAbsolute(raw);
|
|
6576
|
+
if(!abs||typeof abs!=="string")return null;
|
|
6577
|
+
try{
|
|
6578
|
+
var parsed=new URL(abs);
|
|
6579
|
+
// If input is already a proxy URL, unwrap to its target url first
|
|
6580
|
+
// to avoid nested /api/conversion-proxy?url=/api/conversion-proxy?... chains.
|
|
6581
|
+
var p=(parsed.pathname||"");
|
|
6582
|
+
var isProxyPath=p==="/api/conversion-proxy"||p.indexOf("/api/conversion-proxy/")===0||p.indexOf("api/conversion-proxy")!==-1;
|
|
6583
|
+
if(isProxyPath){
|
|
6584
|
+
var nested=parsed.searchParams.get("url")||"";
|
|
6585
|
+
if(nested){
|
|
6586
|
+
try{parsed=new URL(nested);}catch(_){}
|
|
6587
|
+
}
|
|
6588
|
+
}
|
|
6589
|
+
if(parsed.origin!==TARGET_ORIGIN)return null;
|
|
6590
|
+
var root="/api/conversion-proxy";
|
|
6591
|
+
return root+"?password="+encodeURIComponent(PROXY_PASSWORD||"")+"&url="+encodeURIComponent(parsed.toString());
|
|
6592
|
+
}catch(_){
|
|
6593
|
+
return null;
|
|
6594
|
+
}
|
|
6595
|
+
}
|
|
6478
6596
|
var nativeAssign=window.location.assign?window.location.assign.bind(window.location):null;
|
|
6479
6597
|
var nativeReplace=window.location.replace?window.location.replace.bind(window.location):null;
|
|
6480
6598
|
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;}}
|
|
@@ -6548,6 +6666,15 @@ function toProxyNetworkUrl(raw){
|
|
|
6548
6666
|
try{
|
|
6549
6667
|
var base=raw.startsWith("/")?TARGET_ORIGIN:TARGET_PAGE_URL;
|
|
6550
6668
|
var abs=new URL(raw,base);
|
|
6669
|
+
// Unwrap already-proxied URLs first to avoid nested proxy urls.
|
|
6670
|
+
var p0=abs.pathname||"";
|
|
6671
|
+
var isProxyPath0=p0==="/api/conversion-proxy"||p0.indexOf("/api/conversion-proxy/")===0||p0.indexOf("api/conversion-proxy")!==-1;
|
|
6672
|
+
if(isProxyPath0){
|
|
6673
|
+
var nested0=abs.searchParams.get("url")||"";
|
|
6674
|
+
if(nested0){
|
|
6675
|
+
try{abs=new URL(nested0);}catch(_){}
|
|
6676
|
+
}
|
|
6677
|
+
}
|
|
6551
6678
|
// Some embedded scripts build absolute requests against editor origin
|
|
6552
6679
|
// (e.g. https://localhost:4001/api/unstable/graphql.json). Remap those
|
|
6553
6680
|
// paths to target origin first, then proxy as usual.
|