@accelerated-agency/visual-editor 0.1.2 → 0.1.3
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.js +244 -226
- package/package.json +1 -1
package/dist/vite.js
CHANGED
|
@@ -1766,246 +1766,264 @@ var getDefaultAnthropicApiKey = () => {
|
|
|
1766
1766
|
return "";
|
|
1767
1767
|
}
|
|
1768
1768
|
};
|
|
1769
|
-
function
|
|
1769
|
+
function createVisualEditorMiddleware(options) {
|
|
1770
1770
|
const anthropicApiKey = options?.anthropicApiKey || getDefaultAnthropicApiKey();
|
|
1771
1771
|
const enableGenerateTestApi = options?.enableGenerateTestApi ?? true;
|
|
1772
|
-
return {
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
}
|
|
1809
|
-
try {
|
|
1810
|
-
const chunks = [];
|
|
1811
|
-
for await (const chunk of req) chunks.push(chunk);
|
|
1812
|
-
const body = JSON.parse(Buffer.concat(chunks).toString());
|
|
1813
|
-
if (!body.prompt || !body.pageSnapshot) {
|
|
1814
|
-
res.statusCode = 400;
|
|
1815
|
-
res.setHeader("Content-Type", "application/json");
|
|
1816
|
-
res.end(JSON.stringify({ error: "Missing prompt or pageSnapshot" }));
|
|
1817
|
-
return;
|
|
1818
|
-
}
|
|
1819
|
-
const parts = [
|
|
1820
|
-
"## Optimization Goal",
|
|
1821
|
-
body.prompt,
|
|
1822
|
-
"",
|
|
1823
|
-
"## Page Snapshot",
|
|
1824
|
-
JSON.stringify(body.pageSnapshot, null, 2)
|
|
1825
|
-
];
|
|
1826
|
-
const anthropicRes = await fetch("https://api.anthropic.com/v1/messages", {
|
|
1827
|
-
method: "POST",
|
|
1828
|
-
headers: {
|
|
1829
|
-
"Content-Type": "application/json",
|
|
1830
|
-
"x-api-key": anthropicApiKey,
|
|
1831
|
-
"anthropic-version": "2023-06-01"
|
|
1832
|
-
},
|
|
1833
|
-
body: JSON.stringify({
|
|
1834
|
-
model: "claude-sonnet-4-20250514",
|
|
1835
|
-
max_tokens: 4096,
|
|
1836
|
-
system: AI_SYSTEM_PROMPT,
|
|
1837
|
-
messages: [{ role: "user", content: parts.join("\n") }]
|
|
1838
|
-
})
|
|
1839
|
-
});
|
|
1840
|
-
if (!anthropicRes.ok) {
|
|
1841
|
-
const errText = await anthropicRes.text();
|
|
1842
|
-
res.statusCode = 502;
|
|
1843
|
-
res.setHeader("Content-Type", "application/json");
|
|
1844
|
-
res.end(
|
|
1845
|
-
JSON.stringify({
|
|
1846
|
-
error: `Anthropic API returned ${anthropicRes.status}`,
|
|
1847
|
-
detail: errText
|
|
1848
|
-
})
|
|
1849
|
-
);
|
|
1850
|
-
return;
|
|
1851
|
-
}
|
|
1852
|
-
const anthropicData = await anthropicRes.json();
|
|
1853
|
-
const textBlock = anthropicData.content?.find((b) => b.type === "text");
|
|
1854
|
-
if (!textBlock?.text) {
|
|
1855
|
-
res.statusCode = 502;
|
|
1856
|
-
res.setHeader("Content-Type", "application/json");
|
|
1857
|
-
res.end(JSON.stringify({ error: "No text in Anthropic response" }));
|
|
1858
|
-
return;
|
|
1859
|
-
}
|
|
1860
|
-
let cleaned = textBlock.text.trim();
|
|
1861
|
-
if (cleaned.startsWith("```")) {
|
|
1862
|
-
cleaned = cleaned.replace(/^```[a-zA-Z]*\n?/, "").replace(/\n?```\s*$/, "").trim();
|
|
1863
|
-
}
|
|
1864
|
-
let parsed;
|
|
1865
|
-
try {
|
|
1866
|
-
parsed = JSON.parse(cleaned);
|
|
1867
|
-
} catch {
|
|
1868
|
-
res.statusCode = 502;
|
|
1869
|
-
res.setHeader("Content-Type", "application/json");
|
|
1870
|
-
res.end(JSON.stringify({ error: "Invalid JSON from Claude", raw: cleaned }));
|
|
1871
|
-
return;
|
|
1872
|
-
}
|
|
1873
|
-
const now = Date.now();
|
|
1874
|
-
if (parsed.mutations) {
|
|
1875
|
-
parsed.mutations = parsed.mutations.map((m, i) => ({
|
|
1876
|
-
...m,
|
|
1877
|
-
id: m.id || `ai_mut_${String(i + 1).padStart(3, "0")}`,
|
|
1878
|
-
timestamp: now + i
|
|
1879
|
-
}));
|
|
1880
|
-
}
|
|
1881
|
-
res.setHeader("Content-Type", "application/json");
|
|
1882
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1883
|
-
res.end(JSON.stringify(parsed));
|
|
1884
|
-
} catch (err) {
|
|
1885
|
-
res.statusCode = 500;
|
|
1886
|
-
res.setHeader("Content-Type", "application/json");
|
|
1887
|
-
res.end(JSON.stringify({ error: err.message }));
|
|
1888
|
-
}
|
|
1889
|
-
});
|
|
1772
|
+
return async (req, res, next) => {
|
|
1773
|
+
const pathname = (req.url || "").split("?")[0];
|
|
1774
|
+
if (pathname === "/bridge.js") {
|
|
1775
|
+
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
1776
|
+
res.setHeader("Cache-Control", "no-store");
|
|
1777
|
+
res.end(BRIDGE_SCRIPT);
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
if (pathname === "/vvveb-editor") {
|
|
1781
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
1782
|
+
res.setHeader("Cache-Control", "no-store");
|
|
1783
|
+
res.setHeader("X-Frame-Options", "SAMEORIGIN");
|
|
1784
|
+
res.end(buildVvvebEditorHtml());
|
|
1785
|
+
return;
|
|
1786
|
+
}
|
|
1787
|
+
if (pathname === "/api/generate-test" && enableGenerateTestApi) {
|
|
1788
|
+
if (req.method === "OPTIONS") {
|
|
1789
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1790
|
+
res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
|
|
1791
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
1792
|
+
res.statusCode = 204;
|
|
1793
|
+
res.end();
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1796
|
+
if (req.method !== "POST") {
|
|
1797
|
+
res.statusCode = 405;
|
|
1798
|
+
res.end(JSON.stringify({ error: "Method not allowed" }));
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
if (!anthropicApiKey) {
|
|
1802
|
+
res.statusCode = 500;
|
|
1803
|
+
res.setHeader("Content-Type", "application/json");
|
|
1804
|
+
res.end(
|
|
1805
|
+
JSON.stringify({ error: "ANTHROPIC_API_KEY is not configured" })
|
|
1806
|
+
);
|
|
1807
|
+
return;
|
|
1890
1808
|
}
|
|
1891
|
-
|
|
1809
|
+
try {
|
|
1810
|
+
const chunks = [];
|
|
1811
|
+
for await (const chunk of req) chunks.push(chunk);
|
|
1812
|
+
const body = JSON.parse(Buffer.concat(chunks).toString());
|
|
1813
|
+
if (!body.prompt || !body.pageSnapshot) {
|
|
1814
|
+
res.statusCode = 400;
|
|
1815
|
+
res.setHeader("Content-Type", "application/json");
|
|
1816
|
+
res.end(JSON.stringify({ error: "Missing prompt or pageSnapshot" }));
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
const parts = [
|
|
1820
|
+
"## Optimization Goal",
|
|
1821
|
+
body.prompt,
|
|
1822
|
+
"",
|
|
1823
|
+
"## Page Snapshot",
|
|
1824
|
+
JSON.stringify(body.pageSnapshot, null, 2)
|
|
1825
|
+
];
|
|
1826
|
+
const anthropicRes = await fetch("https://api.anthropic.com/v1/messages", {
|
|
1827
|
+
method: "POST",
|
|
1828
|
+
headers: {
|
|
1829
|
+
"Content-Type": "application/json",
|
|
1830
|
+
"x-api-key": anthropicApiKey,
|
|
1831
|
+
"anthropic-version": "2023-06-01"
|
|
1832
|
+
},
|
|
1833
|
+
body: JSON.stringify({
|
|
1834
|
+
model: "claude-sonnet-4-20250514",
|
|
1835
|
+
max_tokens: 4096,
|
|
1836
|
+
system: AI_SYSTEM_PROMPT,
|
|
1837
|
+
messages: [{ role: "user", content: parts.join("\n") }]
|
|
1838
|
+
})
|
|
1839
|
+
});
|
|
1840
|
+
if (!anthropicRes.ok) {
|
|
1841
|
+
const errText = await anthropicRes.text();
|
|
1842
|
+
res.statusCode = 502;
|
|
1843
|
+
res.setHeader("Content-Type", "application/json");
|
|
1844
|
+
res.end(
|
|
1845
|
+
JSON.stringify({
|
|
1846
|
+
error: `Anthropic API returned ${anthropicRes.status}`,
|
|
1847
|
+
detail: errText
|
|
1848
|
+
})
|
|
1849
|
+
);
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1852
|
+
const anthropicData = await anthropicRes.json();
|
|
1853
|
+
const textBlock = anthropicData.content?.find((b) => b.type === "text");
|
|
1854
|
+
if (!textBlock?.text) {
|
|
1855
|
+
res.statusCode = 502;
|
|
1856
|
+
res.setHeader("Content-Type", "application/json");
|
|
1857
|
+
res.end(JSON.stringify({ error: "No text in Anthropic response" }));
|
|
1858
|
+
return;
|
|
1859
|
+
}
|
|
1860
|
+
let cleaned = textBlock.text.trim();
|
|
1861
|
+
if (cleaned.startsWith("```")) {
|
|
1862
|
+
cleaned = cleaned.replace(/^```[a-zA-Z]*\n?/, "").replace(/\n?```\s*$/, "").trim();
|
|
1863
|
+
}
|
|
1864
|
+
let parsed;
|
|
1892
1865
|
try {
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
for await (const chunk of req) {
|
|
1948
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
1949
|
-
}
|
|
1950
|
-
if (chunks.length > 0) requestBody = Buffer.concat(chunks);
|
|
1951
|
-
}
|
|
1952
|
-
const upstream = await fetch(targetUrl, {
|
|
1953
|
-
method,
|
|
1954
|
-
headers: fetchHeaders,
|
|
1955
|
-
body: requestBody ? Buffer.from(requestBody) : null,
|
|
1956
|
-
redirect: "follow"
|
|
1866
|
+
parsed = JSON.parse(cleaned);
|
|
1867
|
+
} catch {
|
|
1868
|
+
res.statusCode = 502;
|
|
1869
|
+
res.setHeader("Content-Type", "application/json");
|
|
1870
|
+
res.end(JSON.stringify({ error: "Invalid JSON from Claude", raw: cleaned }));
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1873
|
+
const now = Date.now();
|
|
1874
|
+
if (parsed.mutations) {
|
|
1875
|
+
parsed.mutations = parsed.mutations.map((m, i) => ({
|
|
1876
|
+
...m,
|
|
1877
|
+
id: m.id || `ai_mut_${String(i + 1).padStart(3, "0")}`,
|
|
1878
|
+
timestamp: now + i
|
|
1879
|
+
}));
|
|
1880
|
+
}
|
|
1881
|
+
res.setHeader("Content-Type", "application/json");
|
|
1882
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1883
|
+
res.end(JSON.stringify(parsed));
|
|
1884
|
+
} catch (err) {
|
|
1885
|
+
res.statusCode = 500;
|
|
1886
|
+
res.setHeader("Content-Type", "application/json");
|
|
1887
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
1888
|
+
}
|
|
1889
|
+
return;
|
|
1890
|
+
}
|
|
1891
|
+
if (pathname.startsWith("/api/proxy")) {
|
|
1892
|
+
try {
|
|
1893
|
+
const url = new URL(req.url || "", "http://localhost");
|
|
1894
|
+
const targetUrl = url.searchParams.get("url");
|
|
1895
|
+
const password = url.searchParams.get("password") || "";
|
|
1896
|
+
if (!targetUrl) {
|
|
1897
|
+
res.statusCode = 400;
|
|
1898
|
+
res.end(JSON.stringify({ error: "Missing url parameter" }));
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
const parsed = new URL(targetUrl);
|
|
1902
|
+
const origin = parsed.origin;
|
|
1903
|
+
const method = (req.method || "GET").toUpperCase();
|
|
1904
|
+
const headers = {
|
|
1905
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
|
|
1906
|
+
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
|
|
1907
|
+
};
|
|
1908
|
+
let cookieHeader = "";
|
|
1909
|
+
if (password) {
|
|
1910
|
+
const passResp = await fetch(`${origin}/password`, {
|
|
1911
|
+
method: "POST",
|
|
1912
|
+
headers: {
|
|
1913
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
1914
|
+
...headers
|
|
1915
|
+
},
|
|
1916
|
+
body: `form_type=storefront_password&utf8=%E2%9C%93&password=${encodeURIComponent(
|
|
1917
|
+
password
|
|
1918
|
+
)}`,
|
|
1919
|
+
redirect: "manual"
|
|
1957
1920
|
});
|
|
1958
|
-
const
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
res.statusCode = 401;
|
|
1973
|
-
res.end(JSON.stringify({ error: "Password authentication failed." }));
|
|
1921
|
+
const setCookies = passResp.headers.getSetCookie?.() || [];
|
|
1922
|
+
cookieHeader = setCookies.map((c) => c.split(";")[0]).join("; ");
|
|
1923
|
+
}
|
|
1924
|
+
const fetchHeaders = { ...headers };
|
|
1925
|
+
Object.entries(req.headers || {}).forEach(([key, value]) => {
|
|
1926
|
+
const lowerKey = key.toLowerCase();
|
|
1927
|
+
if (!value || [
|
|
1928
|
+
"host",
|
|
1929
|
+
"connection",
|
|
1930
|
+
"content-length",
|
|
1931
|
+
"accept-encoding",
|
|
1932
|
+
"origin",
|
|
1933
|
+
"referer"
|
|
1934
|
+
].includes(lowerKey)) {
|
|
1974
1935
|
return;
|
|
1975
1936
|
}
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1937
|
+
fetchHeaders[key] = Array.isArray(value) ? value.join(",") : String(value);
|
|
1938
|
+
});
|
|
1939
|
+
fetchHeaders.Origin = origin;
|
|
1940
|
+
fetchHeaders.Referer = targetUrl;
|
|
1941
|
+
if (cookieHeader) {
|
|
1942
|
+
fetchHeaders.Cookie = fetchHeaders.Cookie ? `${fetchHeaders.Cookie}; ${cookieHeader}` : cookieHeader;
|
|
1943
|
+
}
|
|
1944
|
+
let requestBody;
|
|
1945
|
+
if (!["GET", "HEAD"].includes(method)) {
|
|
1946
|
+
const chunks = [];
|
|
1947
|
+
for await (const chunk of req) {
|
|
1948
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
1986
1949
|
}
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1950
|
+
if (chunks.length > 0) requestBody = Buffer.concat(chunks);
|
|
1951
|
+
}
|
|
1952
|
+
const upstream = await fetch(targetUrl, {
|
|
1953
|
+
method,
|
|
1954
|
+
headers: fetchHeaders,
|
|
1955
|
+
body: requestBody ? Buffer.from(requestBody) : null,
|
|
1956
|
+
redirect: "follow"
|
|
1957
|
+
});
|
|
1958
|
+
const responseContentType = upstream.headers.get("content-type") || "";
|
|
1959
|
+
const isHtmlResponse = responseContentType.includes("text/html");
|
|
1960
|
+
if (!isHtmlResponse) {
|
|
1961
|
+
const binary = Buffer.from(await upstream.arrayBuffer());
|
|
1962
|
+
res.statusCode = upstream.status;
|
|
1963
|
+
if (responseContentType) {
|
|
1964
|
+
res.setHeader("Content-Type", responseContentType);
|
|
1993
1965
|
}
|
|
1994
|
-
const bridgeScript = `<script src="/bridge.js"></script>`;
|
|
1995
|
-
html = html.includes("</body>") ? html.replace("</body>", `${bridgeScript}
|
|
1996
|
-
</body>`) : html + bridgeScript;
|
|
1997
|
-
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
1998
1966
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1999
|
-
res.
|
|
2000
|
-
|
|
2001
|
-
} catch (err) {
|
|
2002
|
-
res.statusCode = 500;
|
|
2003
|
-
res.end(JSON.stringify({ error: err.message }));
|
|
1967
|
+
res.end(binary);
|
|
1968
|
+
return;
|
|
2004
1969
|
}
|
|
2005
|
-
|
|
1970
|
+
let html = await upstream.text();
|
|
1971
|
+
if (html.includes("form_type") && html.includes("storefront_password")) {
|
|
1972
|
+
res.statusCode = 401;
|
|
1973
|
+
res.end(JSON.stringify({ error: "Password authentication failed." }));
|
|
1974
|
+
return;
|
|
1975
|
+
}
|
|
1976
|
+
html = html.replace(/(href|src|action)="\/(?!\/)/g, `$1="${origin}/`);
|
|
1977
|
+
const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1978
|
+
const proxyBase = `/api/proxy?password=${encodeURIComponent(password)}&url=`;
|
|
1979
|
+
html = html.replace(
|
|
1980
|
+
new RegExp(`(href|src|action)="${escapedOrigin}(/[^"]*)"`, "g"),
|
|
1981
|
+
(_, attr, urlPath) => `${attr}="${proxyBase}${encodeURIComponent(origin + urlPath)}"`
|
|
1982
|
+
);
|
|
1983
|
+
if (html.includes("</head>")) {
|
|
1984
|
+
html = html.replace("</head>", `${popupHideCss}
|
|
1985
|
+
</head>`);
|
|
1986
|
+
}
|
|
1987
|
+
const runtimeProxyScript = `<script>(function(){try{var TARGET_ORIGIN=${JSON.stringify(origin)};var TARGET_PAGE_URL=${JSON.stringify(targetUrl)};var PROXY_BASE=${JSON.stringify(`/api/proxy?password=${encodeURIComponent(password)}&url=`)};function isSkippable(raw){if(!raw||typeof raw!=="string")return true;return raw.startsWith("data:")||raw.startsWith("blob:")||raw.startsWith("javascript:")||raw.startsWith("#");}function toProxiedUrl(raw){if(isSkippable(raw))return raw;try{if(raw.startsWith("/api/proxy?"))return raw;var base=raw.startsWith("/")?TARGET_ORIGIN:TARGET_PAGE_URL;var abs=new URL(raw,base);if(abs.origin!==TARGET_ORIGIN)return raw;return PROXY_BASE+encodeURIComponent(abs.toString());}catch(_){return raw;}}if(window.fetch){var _fetch=window.fetch.bind(window);window.fetch=function(input,init){try{if(typeof input==="string"){input=toProxiedUrl(input);}else if(input&&input.url){var next=toProxiedUrl(input.url);if(next!==input.url){input=new Request(next,input);}}}catch(_){}return _fetch(input,init);};}if(window.XMLHttpRequest&&window.XMLHttpRequest.prototype&&window.XMLHttpRequest.prototype.open){var _open=window.XMLHttpRequest.prototype.open;window.XMLHttpRequest.prototype.open=function(method,url){try{arguments[1]=toProxiedUrl(url);}catch(_){}return _open.apply(this,arguments);};}if(window.navigator&&typeof window.navigator.sendBeacon==="function"){var _beacon=window.navigator.sendBeacon.bind(window.navigator);window.navigator.sendBeacon=function(url,data){try{return _beacon(toProxiedUrl(url),data);}catch(_){return _beacon(url,data);}};}if(window.navigator&&window.navigator.serviceWorker&&typeof window.navigator.serviceWorker.register==="function"){window.navigator.serviceWorker.register=function(){return Promise.resolve({scope:"disabled-in-editor-proxy"});};}}catch(_){}})();</script>`;
|
|
1988
|
+
if (html.includes("</head>")) {
|
|
1989
|
+
html = html.replace("</head>", `${runtimeProxyScript}
|
|
1990
|
+
</head>`);
|
|
1991
|
+
} else {
|
|
1992
|
+
html = runtimeProxyScript + html;
|
|
1993
|
+
}
|
|
1994
|
+
const bridgeScript = `<script src="/bridge.js"></script>`;
|
|
1995
|
+
html = html.includes("</body>") ? html.replace("</body>", `${bridgeScript}
|
|
1996
|
+
</body>`) : html + bridgeScript;
|
|
1997
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
1998
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1999
|
+
res.setHeader("X-Frame-Options", "SAMEORIGIN");
|
|
2000
|
+
res.end(html);
|
|
2001
|
+
} catch (err) {
|
|
2002
|
+
res.statusCode = 500;
|
|
2003
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
2004
|
+
}
|
|
2005
|
+
return;
|
|
2006
|
+
}
|
|
2007
|
+
next();
|
|
2008
|
+
};
|
|
2009
|
+
}
|
|
2010
|
+
function visualEditorProxyPlugin(options) {
|
|
2011
|
+
const mw = createVisualEditorMiddleware(options);
|
|
2012
|
+
return {
|
|
2013
|
+
name: "visual-editor-proxy",
|
|
2014
|
+
generateBundle() {
|
|
2015
|
+
this.emitFile({ type: "asset", fileName: "bridge.js", source: BRIDGE_SCRIPT });
|
|
2016
|
+
this.emitFile({ type: "asset", fileName: "vvveb-editor/index.html", source: buildVvvebEditorHtml() });
|
|
2017
|
+
},
|
|
2018
|
+
configureServer(server) {
|
|
2019
|
+
server.middlewares.use(mw);
|
|
2020
|
+
},
|
|
2021
|
+
configurePreviewServer(server) {
|
|
2022
|
+
server.middlewares.use(mw);
|
|
2006
2023
|
}
|
|
2007
2024
|
};
|
|
2008
2025
|
}
|
|
2009
2026
|
export {
|
|
2027
|
+
createVisualEditorMiddleware,
|
|
2010
2028
|
visualEditorProxyPlugin
|
|
2011
2029
|
};
|